blob: 0e21bae3cd198f73ae4eac6ad484c41454420791 [file] [log] [blame]
Vinod Koul71bb8a12017-12-14 11:19:43 +05301// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2// Copyright(c) 2015-17 Intel Corporation.
3
4/*
5 * Soundwire Intel Master Driver
6 */
7
8#include <linux/acpi.h>
Pierre-Louis Bossart79ee6632019-08-21 13:58:20 -05009#include <linux/debugfs.h>
Vinod Koul71bb8a12017-12-14 11:19:43 +053010#include <linux/delay.h>
Paul Gortmaker4abbd782019-04-13 11:12:52 -040011#include <linux/module.h>
Vinod Koul71bb8a12017-12-14 11:19:43 +053012#include <linux/interrupt.h>
Pierre-Louis Bossartdf72b712019-09-16 13:57:38 -050013#include <linux/io.h>
Vinod Koul71bb8a12017-12-14 11:19:43 +053014#include <linux/platform_device.h>
Vinod Koul37a2d222018-04-26 18:38:58 +053015#include <sound/pcm_params.h>
Rander Wangab2c9132020-07-16 23:09:46 +080016#include <linux/pm_runtime.h>
Vinod Koul37a2d222018-04-26 18:38:58 +053017#include <sound/soc.h>
Vinod Koul71bb8a12017-12-14 11:19:43 +053018#include <linux/soundwire/sdw_registers.h>
19#include <linux/soundwire/sdw.h>
20#include <linux/soundwire/sdw_intel.h>
21#include "cadence_master.h"
Pierre-Louis Bossart79ee6632019-08-21 13:58:20 -050022#include "bus.h"
Vinod Koul71bb8a12017-12-14 11:19:43 +053023#include "intel.h"
24
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +080025#define INTEL_MASTER_SUSPEND_DELAY_MS 3000
26
27/*
28 * debug/config flags for the Intel SoundWire Master.
29 *
30 * Since we may have multiple masters active, we can have up to 8
31 * flags reused in each byte, with master0 using the ls-byte, etc.
32 */
33
34#define SDW_INTEL_MASTER_DISABLE_PM_RUNTIME BIT(0)
35#define SDW_INTEL_MASTER_DISABLE_CLOCK_STOP BIT(1)
36
37static int md_flags;
38module_param_named(sdw_md_flags, md_flags, int, 0444);
39MODULE_PARM_DESC(sdw_md_flags, "SoundWire Intel Master device flags (0x0 all off)");
40
Vinod Koul71bb8a12017-12-14 11:19:43 +053041/* Intel SHIM Registers Definition */
42#define SDW_SHIM_LCAP 0x0
43#define SDW_SHIM_LCTL 0x4
44#define SDW_SHIM_IPPTR 0x8
45#define SDW_SHIM_SYNC 0xC
46
Pierre-Louis Bossart7cc6e312019-05-01 10:57:39 -050047#define SDW_SHIM_CTLSCAP(x) (0x010 + 0x60 * (x))
48#define SDW_SHIM_CTLS0CM(x) (0x012 + 0x60 * (x))
49#define SDW_SHIM_CTLS1CM(x) (0x014 + 0x60 * (x))
50#define SDW_SHIM_CTLS2CM(x) (0x016 + 0x60 * (x))
51#define SDW_SHIM_CTLS3CM(x) (0x018 + 0x60 * (x))
52#define SDW_SHIM_PCMSCAP(x) (0x020 + 0x60 * (x))
Vinod Koul71bb8a12017-12-14 11:19:43 +053053
Pierre-Louis Bossart7cc6e312019-05-01 10:57:39 -050054#define SDW_SHIM_PCMSYCHM(x, y) (0x022 + (0x60 * (x)) + (0x2 * (y)))
55#define SDW_SHIM_PCMSYCHC(x, y) (0x042 + (0x60 * (x)) + (0x2 * (y)))
56#define SDW_SHIM_PDMSCAP(x) (0x062 + 0x60 * (x))
57#define SDW_SHIM_IOCTL(x) (0x06C + 0x60 * (x))
58#define SDW_SHIM_CTMCTL(x) (0x06E + 0x60 * (x))
Vinod Koul71bb8a12017-12-14 11:19:43 +053059
60#define SDW_SHIM_WAKEEN 0x190
61#define SDW_SHIM_WAKESTS 0x192
62
63#define SDW_SHIM_LCTL_SPA BIT(0)
64#define SDW_SHIM_LCTL_CPA BIT(8)
65
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +080066#define SDW_SHIM_SYNC_SYNCPRD_VAL_24 (24000 / SDW_CADENCE_GSYNC_KHZ - 1)
67#define SDW_SHIM_SYNC_SYNCPRD_VAL_38_4 (38400 / SDW_CADENCE_GSYNC_KHZ - 1)
Vinod Koul71bb8a12017-12-14 11:19:43 +053068#define SDW_SHIM_SYNC_SYNCPRD GENMASK(14, 0)
69#define SDW_SHIM_SYNC_SYNCCPU BIT(15)
70#define SDW_SHIM_SYNC_CMDSYNC_MASK GENMASK(19, 16)
71#define SDW_SHIM_SYNC_CMDSYNC BIT(16)
72#define SDW_SHIM_SYNC_SYNCGO BIT(24)
73
74#define SDW_SHIM_PCMSCAP_ISS GENMASK(3, 0)
75#define SDW_SHIM_PCMSCAP_OSS GENMASK(7, 4)
76#define SDW_SHIM_PCMSCAP_BSS GENMASK(12, 8)
77
78#define SDW_SHIM_PCMSYCM_LCHN GENMASK(3, 0)
79#define SDW_SHIM_PCMSYCM_HCHN GENMASK(7, 4)
80#define SDW_SHIM_PCMSYCM_STREAM GENMASK(13, 8)
81#define SDW_SHIM_PCMSYCM_DIR BIT(15)
82
83#define SDW_SHIM_PDMSCAP_ISS GENMASK(3, 0)
84#define SDW_SHIM_PDMSCAP_OSS GENMASK(7, 4)
85#define SDW_SHIM_PDMSCAP_BSS GENMASK(12, 8)
86#define SDW_SHIM_PDMSCAP_CPSS GENMASK(15, 13)
87
88#define SDW_SHIM_IOCTL_MIF BIT(0)
89#define SDW_SHIM_IOCTL_CO BIT(1)
90#define SDW_SHIM_IOCTL_COE BIT(2)
91#define SDW_SHIM_IOCTL_DO BIT(3)
92#define SDW_SHIM_IOCTL_DOE BIT(4)
93#define SDW_SHIM_IOCTL_BKE BIT(5)
94#define SDW_SHIM_IOCTL_WPDD BIT(6)
95#define SDW_SHIM_IOCTL_CIBD BIT(8)
96#define SDW_SHIM_IOCTL_DIBD BIT(9)
97
98#define SDW_SHIM_CTMCTL_DACTQE BIT(0)
99#define SDW_SHIM_CTMCTL_DODS BIT(1)
100#define SDW_SHIM_CTMCTL_DOAIS GENMASK(4, 3)
101
102#define SDW_SHIM_WAKEEN_ENABLE BIT(0)
103#define SDW_SHIM_WAKESTS_STATUS BIT(0)
104
105/* Intel ALH Register definitions */
Pierre-Louis Bossart7cc6e312019-05-01 10:57:39 -0500106#define SDW_ALH_STRMZCFG(x) (0x000 + (0x4 * (x)))
Pierre-Louis Bossart79ee6632019-08-21 13:58:20 -0500107#define SDW_ALH_NUM_STREAMS 64
Vinod Koul71bb8a12017-12-14 11:19:43 +0530108
109#define SDW_ALH_STRMZCFG_DMAT_VAL 0x3
110#define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0)
111#define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16)
112
Vinod Koulc46302e2018-04-26 18:39:05 +0530113enum intel_pdi_type {
114 INTEL_PDI_IN = 0,
115 INTEL_PDI_OUT = 1,
116 INTEL_PDI_BD = 2,
117};
118
Vinod Koul71bb8a12017-12-14 11:19:43 +0530119#define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
120
121/*
122 * Read, write helpers for HW registers
123 */
124static inline int intel_readl(void __iomem *base, int offset)
125{
126 return readl(base + offset);
127}
128
129static inline void intel_writel(void __iomem *base, int offset, int value)
130{
131 writel(value, base + offset);
132}
133
134static inline u16 intel_readw(void __iomem *base, int offset)
135{
136 return readw(base + offset);
137}
138
139static inline void intel_writew(void __iomem *base, int offset, u16 value)
140{
141 writew(value, base + offset);
142}
143
Pierre-Louis Bossart7d2845d2020-07-16 23:09:39 +0800144static int intel_wait_bit(void __iomem *base, int offset, u32 mask, u32 target)
Vinod Koul71bb8a12017-12-14 11:19:43 +0530145{
146 int timeout = 10;
147 u32 reg_read;
148
Vinod Koul71bb8a12017-12-14 11:19:43 +0530149 do {
150 reg_read = readl(base + offset);
Pierre-Louis Bossart7d2845d2020-07-16 23:09:39 +0800151 if ((reg_read & mask) == target)
Vinod Koul71bb8a12017-12-14 11:19:43 +0530152 return 0;
153
154 timeout--;
Pierre-Louis Bossart7d2845d2020-07-16 23:09:39 +0800155 usleep_range(50, 100);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530156 } while (timeout != 0);
157
158 return -EAGAIN;
159}
160
Pierre-Louis Bossart7d2845d2020-07-16 23:09:39 +0800161static int intel_clear_bit(void __iomem *base, int offset, u32 value, u32 mask)
162{
163 writel(value, base + offset);
164 return intel_wait_bit(base, offset, mask, 0);
165}
166
Vinod Koul71bb8a12017-12-14 11:19:43 +0530167static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
168{
Vinod Koul71bb8a12017-12-14 11:19:43 +0530169 writel(value, base + offset);
Pierre-Louis Bossart7d2845d2020-07-16 23:09:39 +0800170 return intel_wait_bit(base, offset, mask, mask);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530171}
172
173/*
Pierre-Louis Bossart79ee6632019-08-21 13:58:20 -0500174 * debugfs
175 */
176#ifdef CONFIG_DEBUG_FS
177
178#define RD_BUF (2 * PAGE_SIZE)
179
180static ssize_t intel_sprintf(void __iomem *mem, bool l,
181 char *buf, size_t pos, unsigned int reg)
182{
183 int value;
184
185 if (l)
186 value = intel_readl(mem, reg);
187 else
188 value = intel_readw(mem, reg);
189
190 return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
191}
192
193static int intel_reg_show(struct seq_file *s_file, void *data)
194{
195 struct sdw_intel *sdw = s_file->private;
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600196 void __iomem *s = sdw->link_res->shim;
197 void __iomem *a = sdw->link_res->alh;
Pierre-Louis Bossart79ee6632019-08-21 13:58:20 -0500198 char *buf;
199 ssize_t ret;
200 int i, j;
201 unsigned int links, reg;
202
203 buf = kzalloc(RD_BUF, GFP_KERNEL);
204 if (!buf)
205 return -ENOMEM;
206
207 links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0);
208
209 ret = scnprintf(buf, RD_BUF, "Register Value\n");
210 ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
211
212 for (i = 0; i < links; i++) {
213 reg = SDW_SHIM_LCAP + i * 4;
214 ret += intel_sprintf(s, true, buf, ret, reg);
215 }
216
217 for (i = 0; i < links; i++) {
218 ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
219 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
220 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
221 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
222 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
223 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
224 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
225
226 ret += scnprintf(buf + ret, RD_BUF - ret, "\n PCMSyCH registers\n");
227
228 /*
229 * the value 10 is the number of PDIs. We will need a
230 * cleanup to remove hard-coded Intel configurations
231 * from cadence_master.c
232 */
233 for (j = 0; j < 10; j++) {
234 ret += intel_sprintf(s, false, buf, ret,
235 SDW_SHIM_PCMSYCHM(i, j));
236 ret += intel_sprintf(s, false, buf, ret,
237 SDW_SHIM_PCMSYCHC(i, j));
238 }
239 ret += scnprintf(buf + ret, RD_BUF - ret, "\n PDMSCAP, IOCTL, CTMCTL\n");
240
241 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
242 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
243 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
244 }
245
246 ret += scnprintf(buf + ret, RD_BUF - ret, "\nWake registers\n");
247 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
248 ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
249
250 ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH STRMzCFG\n");
251 for (i = 0; i < SDW_ALH_NUM_STREAMS; i++)
252 ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
253
254 seq_printf(s_file, "%s", buf);
255 kfree(buf);
256
257 return 0;
258}
259DEFINE_SHOW_ATTRIBUTE(intel_reg);
260
261static void intel_debugfs_init(struct sdw_intel *sdw)
262{
263 struct dentry *root = sdw->cdns.bus.debugfs;
264
265 if (!root)
266 return;
267
268 sdw->debugfs = debugfs_create_dir("intel-sdw", root);
269
270 debugfs_create_file("intel-registers", 0400, sdw->debugfs, sdw,
271 &intel_reg_fops);
272
273 sdw_cdns_debugfs_init(&sdw->cdns, sdw->debugfs);
274}
275
276static void intel_debugfs_exit(struct sdw_intel *sdw)
277{
278 debugfs_remove_recursive(sdw->debugfs);
279}
280#else
281static void intel_debugfs_init(struct sdw_intel *sdw) {}
282static void intel_debugfs_exit(struct sdw_intel *sdw) {}
283#endif /* CONFIG_DEBUG_FS */
284
285/*
Vinod Koul71bb8a12017-12-14 11:19:43 +0530286 * shim ops
287 */
288
289static int intel_link_power_up(struct sdw_intel *sdw)
290{
291 unsigned int link_id = sdw->instance;
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600292 void __iomem *shim = sdw->link_res->shim;
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800293 u32 *shim_mask = sdw->link_res->shim_mask;
294 struct sdw_bus *bus = &sdw->cdns.bus;
295 struct sdw_master_prop *prop = &bus->prop;
Vinod Koul71bb8a12017-12-14 11:19:43 +0530296 int spa_mask, cpa_mask;
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800297 int link_control;
298 int ret = 0;
299 u32 syncprd;
300 u32 sync_reg;
301
302 mutex_lock(sdw->link_res->shim_lock);
303
304 /*
305 * The hardware relies on an internal counter, typically 4kHz,
306 * to generate the SoundWire SSP - which defines a 'safe'
307 * synchronization point between commands and audio transport
308 * and allows for multi link synchronization. The SYNCPRD value
309 * is only dependent on the oscillator clock provided to
310 * the IP, so adjust based on _DSD properties reported in DSDT
311 * tables. The values reported are based on either 24MHz
312 * (CNL/CML) or 38.4 MHz (ICL/TGL+).
313 */
314 if (prop->mclk_freq % 6000000)
315 syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_38_4;
316 else
317 syncprd = SDW_SHIM_SYNC_SYNCPRD_VAL_24;
318
319 if (!*shim_mask) {
320 /* we first need to program the SyncPRD/CPU registers */
321 dev_dbg(sdw->cdns.dev,
322 "%s: first link up, programming SYNCPRD\n", __func__);
323
324 /* set SyncPRD period */
325 sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
326 sync_reg |= (syncprd <<
327 SDW_REG_SHIFT(SDW_SHIM_SYNC_SYNCPRD));
328
329 /* Set SyncCPU bit */
330 sync_reg |= SDW_SHIM_SYNC_SYNCCPU;
331 intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
332 }
Vinod Koul71bb8a12017-12-14 11:19:43 +0530333
334 /* Link power up sequence */
335 link_control = intel_readl(shim, SDW_SHIM_LCTL);
336 spa_mask = (SDW_SHIM_LCTL_SPA << link_id);
337 cpa_mask = (SDW_SHIM_LCTL_CPA << link_id);
338 link_control |= spa_mask;
339
340 ret = intel_set_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800341 if (ret < 0) {
342 dev_err(sdw->cdns.dev, "Failed to power up link: %d\n", ret);
343 goto out;
344 }
345
346 if (!*shim_mask) {
347 /* SyncCPU will change once link is active */
348 ret = intel_wait_bit(shim, SDW_SHIM_SYNC,
349 SDW_SHIM_SYNC_SYNCCPU, 0);
350 if (ret < 0) {
351 dev_err(sdw->cdns.dev,
352 "Failed to set SHIM_SYNC: %d\n", ret);
353 goto out;
354 }
355 }
356
357 *shim_mask |= BIT(link_id);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530358
359 sdw->cdns.link_up = true;
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800360out:
361 mutex_unlock(sdw->link_res->shim_lock);
362
363 return ret;
Vinod Koul71bb8a12017-12-14 11:19:43 +0530364}
365
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800366/* this needs to be called with shim_lock */
367static void intel_shim_glue_to_master_ip(struct sdw_intel *sdw)
Vinod Koul71bb8a12017-12-14 11:19:43 +0530368{
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600369 void __iomem *shim = sdw->link_res->shim;
Vinod Koul71bb8a12017-12-14 11:19:43 +0530370 unsigned int link_id = sdw->instance;
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800371 u16 ioctl;
Vinod Koul71bb8a12017-12-14 11:19:43 +0530372
373 /* Switch to MIP from Glue logic */
374 ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));
375
376 ioctl &= ~(SDW_SHIM_IOCTL_DOE);
377 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800378 usleep_range(10, 15);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530379
380 ioctl &= ~(SDW_SHIM_IOCTL_DO);
381 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800382 usleep_range(10, 15);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530383
384 ioctl |= (SDW_SHIM_IOCTL_MIF);
385 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800386 usleep_range(10, 15);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530387
388 ioctl &= ~(SDW_SHIM_IOCTL_BKE);
389 ioctl &= ~(SDW_SHIM_IOCTL_COE);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530390 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800391 usleep_range(10, 15);
392
393 /* at this point Master IP has full control of the I/Os */
394}
395
396/* this needs to be called with shim_lock */
397static void intel_shim_master_ip_to_glue(struct sdw_intel *sdw)
398{
399 unsigned int link_id = sdw->instance;
400 void __iomem *shim = sdw->link_res->shim;
401 u16 ioctl;
402
403 /* Glue logic */
404 ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));
405 ioctl |= SDW_SHIM_IOCTL_BKE;
406 ioctl |= SDW_SHIM_IOCTL_COE;
407 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
408 usleep_range(10, 15);
409
410 ioctl &= ~(SDW_SHIM_IOCTL_MIF);
411 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
412 usleep_range(10, 15);
413
414 /* at this point Integration Glue has full control of the I/Os */
415}
416
417static int intel_shim_init(struct sdw_intel *sdw, bool clock_stop)
418{
419 void __iomem *shim = sdw->link_res->shim;
420 unsigned int link_id = sdw->instance;
421 int ret = 0;
422 u16 ioctl = 0, act = 0;
423
424 mutex_lock(sdw->link_res->shim_lock);
425
426 /* Initialize Shim */
427 ioctl |= SDW_SHIM_IOCTL_BKE;
428 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
429 usleep_range(10, 15);
430
431 ioctl |= SDW_SHIM_IOCTL_WPDD;
432 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
433 usleep_range(10, 15);
434
435 ioctl |= SDW_SHIM_IOCTL_DO;
436 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
437 usleep_range(10, 15);
438
439 ioctl |= SDW_SHIM_IOCTL_DOE;
440 intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
441 usleep_range(10, 15);
442
443 intel_shim_glue_to_master_ip(sdw);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530444
445 act |= 0x1 << SDW_REG_SHIFT(SDW_SHIM_CTMCTL_DOAIS);
446 act |= SDW_SHIM_CTMCTL_DACTQE;
447 act |= SDW_SHIM_CTMCTL_DODS;
448 intel_writew(shim, SDW_SHIM_CTMCTL(link_id), act);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800449 usleep_range(10, 15);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530450
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800451 mutex_unlock(sdw->link_res->shim_lock);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530452
Vinod Koul71bb8a12017-12-14 11:19:43 +0530453 return ret;
454}
455
Rander Wangab2c9132020-07-16 23:09:46 +0800456static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800457{
458 void __iomem *shim = sdw->link_res->shim;
459 unsigned int link_id = sdw->instance;
460 u16 wake_en, wake_sts;
461
462 mutex_lock(sdw->link_res->shim_lock);
463 wake_en = intel_readw(shim, SDW_SHIM_WAKEEN);
464
465 if (wake_enable) {
466 /* Enable the wakeup */
467 wake_en |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
468 intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
469 } else {
470 /* Disable the wake up interrupt */
471 wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id);
472 intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
473
474 /* Clear wake status */
475 wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
476 wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
477 intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts);
478 }
479 mutex_unlock(sdw->link_res->shim_lock);
480}
481
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +0800482static int intel_link_power_down(struct sdw_intel *sdw)
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800483{
484 int link_control, spa_mask, cpa_mask;
485 unsigned int link_id = sdw->instance;
486 void __iomem *shim = sdw->link_res->shim;
487 u32 *shim_mask = sdw->link_res->shim_mask;
488 int ret = 0;
489
490 mutex_lock(sdw->link_res->shim_lock);
491
492 intel_shim_master_ip_to_glue(sdw);
493
494 /* Link power down sequence */
495 link_control = intel_readl(shim, SDW_SHIM_LCTL);
496 spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id);
497 cpa_mask = (SDW_SHIM_LCTL_CPA << link_id);
498 link_control &= spa_mask;
499
500 ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
501
502 if (!(*shim_mask & BIT(link_id)))
503 dev_err(sdw->cdns.dev,
504 "%s: Unbalanced power-up/down calls\n", __func__);
505
506 *shim_mask &= ~BIT(link_id);
507
508 mutex_unlock(sdw->link_res->shim_lock);
509
Vinod Koul71bb8a12017-12-14 11:19:43 +0530510 if (ret < 0)
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800511 return ret;
512
513 sdw->cdns.link_up = false;
514 return 0;
515}
516
Pierre-Louis Bossart02629e452020-07-16 23:09:41 +0800517static void intel_shim_sync_arm(struct sdw_intel *sdw)
518{
519 void __iomem *shim = sdw->link_res->shim;
520 u32 sync_reg;
521
522 mutex_lock(sdw->link_res->shim_lock);
523
524 /* update SYNC register */
525 sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
526 sync_reg |= (SDW_SHIM_SYNC_CMDSYNC << sdw->instance);
527 intel_writel(shim, SDW_SHIM_SYNC, sync_reg);
528
529 mutex_unlock(sdw->link_res->shim_lock);
530}
531
Pierre-Louis Bossart437e3282020-07-16 23:09:42 +0800532static int intel_shim_sync_go_unlocked(struct sdw_intel *sdw)
533{
534 void __iomem *shim = sdw->link_res->shim;
535 u32 sync_reg;
536 int ret;
537
538 /* Read SYNC register */
539 sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
540
541 /*
542 * Set SyncGO bit to synchronously trigger a bank switch for
543 * all the masters. A write to SYNCGO bit clears CMDSYNC bit for all
544 * the Masters.
545 */
546 sync_reg |= SDW_SHIM_SYNC_SYNCGO;
547
548 ret = intel_clear_bit(shim, SDW_SHIM_SYNC, sync_reg,
549 SDW_SHIM_SYNC_SYNCGO);
550
551 if (ret < 0)
552 dev_err(sdw->cdns.dev, "SyncGO clear failed: %d\n", ret);
Vinod Koul71bb8a12017-12-14 11:19:43 +0530553
554 return ret;
555}
556
Vinod Koul37a2d222018-04-26 18:38:58 +0530557/*
558 * PDI routines
559 */
560static void intel_pdi_init(struct sdw_intel *sdw,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500561 struct sdw_cdns_stream_config *config)
Vinod Koul37a2d222018-04-26 18:38:58 +0530562{
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600563 void __iomem *shim = sdw->link_res->shim;
Vinod Koul37a2d222018-04-26 18:38:58 +0530564 unsigned int link_id = sdw->instance;
565 int pcm_cap, pdm_cap;
566
567 /* PCM Stream Capability */
568 pcm_cap = intel_readw(shim, SDW_SHIM_PCMSCAP(link_id));
569
570 config->pcm_bd = (pcm_cap & SDW_SHIM_PCMSCAP_BSS) >>
571 SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_BSS);
572 config->pcm_in = (pcm_cap & SDW_SHIM_PCMSCAP_ISS) >>
573 SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_ISS);
574 config->pcm_out = (pcm_cap & SDW_SHIM_PCMSCAP_OSS) >>
575 SDW_REG_SHIFT(SDW_SHIM_PCMSCAP_OSS);
576
Pierre-Louis Bossart121f4362019-05-22 14:47:29 -0500577 dev_dbg(sdw->cdns.dev, "PCM cap bd:%d in:%d out:%d\n",
578 config->pcm_bd, config->pcm_in, config->pcm_out);
579
Vinod Koul37a2d222018-04-26 18:38:58 +0530580 /* PDM Stream Capability */
581 pdm_cap = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
582
583 config->pdm_bd = (pdm_cap & SDW_SHIM_PDMSCAP_BSS) >>
584 SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_BSS);
585 config->pdm_in = (pdm_cap & SDW_SHIM_PDMSCAP_ISS) >>
586 SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_ISS);
587 config->pdm_out = (pdm_cap & SDW_SHIM_PDMSCAP_OSS) >>
588 SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_OSS);
Pierre-Louis Bossart121f4362019-05-22 14:47:29 -0500589
590 dev_dbg(sdw->cdns.dev, "PDM cap bd:%d in:%d out:%d\n",
591 config->pdm_bd, config->pdm_in, config->pdm_out);
Vinod Koul37a2d222018-04-26 18:38:58 +0530592}
593
594static int
595intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
596{
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600597 void __iomem *shim = sdw->link_res->shim;
Vinod Koul37a2d222018-04-26 18:38:58 +0530598 unsigned int link_id = sdw->instance;
599 int count;
600
601 if (pcm) {
602 count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
Pierre-Louis Bossart18046332019-08-05 19:55:07 -0500603
604 /*
605 * WORKAROUND: on all existing Intel controllers, pdi
606 * number 2 reports channel count as 1 even though it
607 * supports 8 channels. Performing hardcoding for pdi
608 * number 2.
609 */
610 if (pdi_num == 2)
611 count = 7;
612
Vinod Koul37a2d222018-04-26 18:38:58 +0530613 } else {
614 count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
615 count = ((count & SDW_SHIM_PDMSCAP_CPSS) >>
616 SDW_REG_SHIFT(SDW_SHIM_PDMSCAP_CPSS));
617 }
618
619 /* zero based values for channel count in register */
620 count++;
621
622 return count;
623}
624
625static int intel_pdi_get_ch_update(struct sdw_intel *sdw,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500626 struct sdw_cdns_pdi *pdi,
627 unsigned int num_pdi,
628 unsigned int *num_ch, bool pcm)
Vinod Koul37a2d222018-04-26 18:38:58 +0530629{
630 int i, ch_count = 0;
631
632 for (i = 0; i < num_pdi; i++) {
633 pdi->ch_count = intel_pdi_get_ch_cap(sdw, pdi->num, pcm);
634 ch_count += pdi->ch_count;
635 pdi++;
636 }
637
638 *num_ch = ch_count;
639 return 0;
640}
641
642static int intel_pdi_stream_ch_update(struct sdw_intel *sdw,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500643 struct sdw_cdns_streams *stream, bool pcm)
Vinod Koul37a2d222018-04-26 18:38:58 +0530644{
645 intel_pdi_get_ch_update(sdw, stream->bd, stream->num_bd,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500646 &stream->num_ch_bd, pcm);
Vinod Koul37a2d222018-04-26 18:38:58 +0530647
648 intel_pdi_get_ch_update(sdw, stream->in, stream->num_in,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500649 &stream->num_ch_in, pcm);
Vinod Koul37a2d222018-04-26 18:38:58 +0530650
651 intel_pdi_get_ch_update(sdw, stream->out, stream->num_out,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500652 &stream->num_ch_out, pcm);
Vinod Koul37a2d222018-04-26 18:38:58 +0530653
654 return 0;
655}
656
657static int intel_pdi_ch_update(struct sdw_intel *sdw)
658{
659 /* First update PCM streams followed by PDM streams */
660 intel_pdi_stream_ch_update(sdw, &sdw->cdns.pcm, true);
661 intel_pdi_stream_ch_update(sdw, &sdw->cdns.pdm, false);
662
663 return 0;
664}
665
666static void
667intel_pdi_shim_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
668{
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600669 void __iomem *shim = sdw->link_res->shim;
Vinod Koul37a2d222018-04-26 18:38:58 +0530670 unsigned int link_id = sdw->instance;
671 int pdi_conf = 0;
672
Pierre-Louis Bossartc134f912019-10-22 18:29:48 -0500673 /* the Bulk and PCM streams are not contiguous */
674 pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
675 if (pdi->num >= 2)
676 pdi->intel_alh_id += 2;
Vinod Koul37a2d222018-04-26 18:38:58 +0530677
678 /*
679 * Program stream parameters to stream SHIM register
680 * This is applicable for PCM stream only.
681 */
682 if (pdi->type != SDW_STREAM_PCM)
683 return;
684
685 if (pdi->dir == SDW_DATA_DIR_RX)
686 pdi_conf |= SDW_SHIM_PCMSYCM_DIR;
687 else
688 pdi_conf &= ~(SDW_SHIM_PCMSYCM_DIR);
689
690 pdi_conf |= (pdi->intel_alh_id <<
691 SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_STREAM));
692 pdi_conf |= (pdi->l_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_LCHN));
693 pdi_conf |= (pdi->h_ch_num << SDW_REG_SHIFT(SDW_SHIM_PCMSYCM_HCHN));
694
695 intel_writew(shim, SDW_SHIM_PCMSYCHM(link_id, pdi->num), pdi_conf);
696}
697
698static void
699intel_pdi_alh_configure(struct sdw_intel *sdw, struct sdw_cdns_pdi *pdi)
700{
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600701 void __iomem *alh = sdw->link_res->alh;
Vinod Koul37a2d222018-04-26 18:38:58 +0530702 unsigned int link_id = sdw->instance;
703 unsigned int conf;
704
Pierre-Louis Bossartc134f912019-10-22 18:29:48 -0500705 /* the Bulk and PCM streams are not contiguous */
706 pdi->intel_alh_id = (link_id * 16) + pdi->num + 3;
707 if (pdi->num >= 2)
708 pdi->intel_alh_id += 2;
Vinod Koul37a2d222018-04-26 18:38:58 +0530709
710 /* Program Stream config ALH register */
711 conf = intel_readl(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id));
712
713 conf |= (SDW_ALH_STRMZCFG_DMAT_VAL <<
714 SDW_REG_SHIFT(SDW_ALH_STRMZCFG_DMAT));
715
716 conf |= ((pdi->ch_count - 1) <<
717 SDW_REG_SHIFT(SDW_ALH_STRMZCFG_CHN));
718
719 intel_writel(alh, SDW_ALH_STRMZCFG(pdi->intel_alh_id), conf);
720}
721
Rander Wang4b206d32019-12-11 19:45:02 -0600722static int intel_params_stream(struct sdw_intel *sdw,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500723 struct snd_pcm_substream *substream,
724 struct snd_soc_dai *dai,
Rander Wang4b206d32019-12-11 19:45:02 -0600725 struct snd_pcm_hw_params *hw_params,
726 int link_id, int alh_stream_id)
Vinod Koulc46302e2018-04-26 18:39:05 +0530727{
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600728 struct sdw_intel_link_res *res = sdw->link_res;
Rander Wang4b206d32019-12-11 19:45:02 -0600729 struct sdw_intel_stream_params_data params_data;
Pierre-Louis Bossart05c8afe42019-08-05 19:55:06 -0500730
Rander Wang4b206d32019-12-11 19:45:02 -0600731 params_data.substream = substream;
732 params_data.dai = dai;
733 params_data.hw_params = hw_params;
734 params_data.link_id = link_id;
735 params_data.alh_stream_id = alh_stream_id;
Vinod Koulc46302e2018-04-26 18:39:05 +0530736
Rander Wang4b206d32019-12-11 19:45:02 -0600737 if (res->ops && res->ops->params_stream && res->dev)
738 return res->ops->params_stream(res->dev,
739 &params_data);
Vinod Koulc46302e2018-04-26 18:39:05 +0530740 return -EIO;
741}
742
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -0600743static int intel_free_stream(struct sdw_intel *sdw,
744 struct snd_pcm_substream *substream,
745 struct snd_soc_dai *dai,
746 int link_id)
747{
748 struct sdw_intel_link_res *res = sdw->link_res;
749 struct sdw_intel_stream_free_data free_data;
750
751 free_data.substream = substream;
752 free_data.dai = dai;
753 free_data.link_id = link_id;
754
755 if (res->ops && res->ops->free_stream && res->dev)
756 return res->ops->free_stream(res->dev,
757 &free_data);
758
759 return 0;
760}
761
Vinod Koulc46302e2018-04-26 18:39:05 +0530762/*
Shreyas NC30246e22018-07-27 14:44:17 +0530763 * bank switch routines
764 */
765
766static int intel_pre_bank_switch(struct sdw_bus *bus)
767{
768 struct sdw_cdns *cdns = bus_to_cdns(bus);
769 struct sdw_intel *sdw = cdns_to_intel(cdns);
Shreyas NC30246e22018-07-27 14:44:17 +0530770
771 /* Write to register only for multi-link */
772 if (!bus->multi_link)
773 return 0;
774
Pierre-Louis Bossart02629e452020-07-16 23:09:41 +0800775 intel_shim_sync_arm(sdw);
Shreyas NC30246e22018-07-27 14:44:17 +0530776
777 return 0;
778}
779
780static int intel_post_bank_switch(struct sdw_bus *bus)
781{
782 struct sdw_cdns *cdns = bus_to_cdns(bus);
783 struct sdw_intel *sdw = cdns_to_intel(cdns);
Pierre-Louis Bossart25234862020-02-14 19:47:36 -0600784 void __iomem *shim = sdw->link_res->shim;
Shreyas NC30246e22018-07-27 14:44:17 +0530785 int sync_reg, ret;
786
787 /* Write to register only for multi-link */
788 if (!bus->multi_link)
789 return 0;
790
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800791 mutex_lock(sdw->link_res->shim_lock);
792
Shreyas NC30246e22018-07-27 14:44:17 +0530793 /* Read SYNC register */
794 sync_reg = intel_readl(shim, SDW_SHIM_SYNC);
795
796 /*
797 * post_bank_switch() ops is called from the bus in loop for
798 * all the Masters in the steam with the expectation that
799 * we trigger the bankswitch for the only first Master in the list
800 * and do nothing for the other Masters
801 *
802 * So, set the SYNCGO bit only if CMDSYNC bit is set for any Master.
803 */
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800804 if (!(sync_reg & SDW_SHIM_SYNC_CMDSYNC_MASK)) {
805 ret = 0;
806 goto unlock;
807 }
Shreyas NC30246e22018-07-27 14:44:17 +0530808
Pierre-Louis Bossart437e3282020-07-16 23:09:42 +0800809 ret = intel_shim_sync_go_unlocked(sdw);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +0800810unlock:
811 mutex_unlock(sdw->link_res->shim_lock);
Shreyas NC30246e22018-07-27 14:44:17 +0530812
Shreyas NC30246e22018-07-27 14:44:17 +0530813 if (ret < 0)
Pierre-Louis Bossart17ed5be2019-05-01 10:57:45 -0500814 dev_err(sdw->cdns.dev, "Post bank switch failed: %d\n", ret);
Shreyas NC30246e22018-07-27 14:44:17 +0530815
816 return ret;
817}
818
819/*
Vinod Koulc46302e2018-04-26 18:39:05 +0530820 * DAI routines
821 */
822
Rander Wang5e7484d2020-02-14 19:47:39 -0600823static int intel_startup(struct snd_pcm_substream *substream,
824 struct snd_soc_dai *dai)
825{
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +0800826 struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
827 int ret;
828
829 ret = pm_runtime_get_sync(cdns->dev);
830 if (ret < 0 && ret != -EACCES) {
831 dev_err_ratelimited(cdns->dev,
832 "pm_runtime_get_sync failed in %s, ret %d\n",
833 __func__, ret);
834 pm_runtime_put_noidle(cdns->dev);
835 return ret;
836 }
Pierre-Louis Bossartff16d1e2020-07-01 02:43:54 +0800837 return 0;
Rander Wang5e7484d2020-02-14 19:47:39 -0600838}
839
Vinod Koulc46302e2018-04-26 18:39:05 +0530840static int intel_hw_params(struct snd_pcm_substream *substream,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500841 struct snd_pcm_hw_params *params,
842 struct snd_soc_dai *dai)
Vinod Koulc46302e2018-04-26 18:39:05 +0530843{
844 struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
845 struct sdw_intel *sdw = cdns_to_intel(cdns);
846 struct sdw_cdns_dma_data *dma;
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500847 struct sdw_cdns_pdi *pdi;
Vinod Koulc46302e2018-04-26 18:39:05 +0530848 struct sdw_stream_config sconfig;
849 struct sdw_port_config *pconfig;
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500850 int ch, dir;
851 int ret;
Vinod Koulc46302e2018-04-26 18:39:05 +0530852 bool pcm = true;
853
854 dma = snd_soc_dai_get_dma_data(dai, substream);
855 if (!dma)
856 return -EIO;
857
858 ch = params_channels(params);
859 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
860 dir = SDW_DATA_DIR_RX;
861 else
862 dir = SDW_DATA_DIR_TX;
863
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500864 if (dma->stream_type == SDW_STREAM_PDM)
Vinod Koulc46302e2018-04-26 18:39:05 +0530865 pcm = false;
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500866
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500867 if (pcm)
Bard Liao1b53385e2019-09-16 14:23:48 -0500868 pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pcm, ch, dir, dai->id);
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500869 else
Bard Liao1b53385e2019-09-16 14:23:48 -0500870 pdi = sdw_cdns_alloc_pdi(cdns, &cdns->pdm, ch, dir, dai->id);
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500871
872 if (!pdi) {
873 ret = -EINVAL;
874 goto error;
Vinod Koulc46302e2018-04-26 18:39:05 +0530875 }
876
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500877 /* do run-time configurations for SHIM, ALH and PDI/PORT */
878 intel_pdi_shim_configure(sdw, pdi);
879 intel_pdi_alh_configure(sdw, pdi);
880 sdw_cdns_config_stream(cdns, ch, dir, pdi);
Vinod Koulc46302e2018-04-26 18:39:05 +0530881
Vinod Koulc46302e2018-04-26 18:39:05 +0530882
883 /* Inform DSP about PDI stream number */
Rander Wang4b206d32019-12-11 19:45:02 -0600884 ret = intel_params_stream(sdw, substream, dai, params,
885 sdw->instance,
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500886 pdi->intel_alh_id);
887 if (ret)
888 goto error;
Vinod Koulc46302e2018-04-26 18:39:05 +0530889
890 sconfig.direction = dir;
891 sconfig.ch_count = ch;
892 sconfig.frame_rate = params_rate(params);
893 sconfig.type = dma->stream_type;
894
895 if (dma->stream_type == SDW_STREAM_PDM) {
896 sconfig.frame_rate *= 50;
897 sconfig.bps = 1;
898 } else {
899 sconfig.bps = snd_pcm_format_width(params_format(params));
900 }
901
902 /* Port configuration */
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500903 pconfig = kcalloc(1, sizeof(*pconfig), GFP_KERNEL);
Vinod Koulc46302e2018-04-26 18:39:05 +0530904 if (!pconfig) {
905 ret = -ENOMEM;
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500906 goto error;
Vinod Koulc46302e2018-04-26 18:39:05 +0530907 }
908
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500909 pconfig->num = pdi->num;
910 pconfig->ch_mask = (1 << ch) - 1;
Vinod Koulc46302e2018-04-26 18:39:05 +0530911
912 ret = sdw_stream_add_master(&cdns->bus, &sconfig,
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500913 pconfig, 1, dma->stream);
914 if (ret)
Pierre-Louis Bossart17ed5be2019-05-01 10:57:45 -0500915 dev_err(cdns->dev, "add master to stream failed:%d\n", ret);
Vinod Koulc46302e2018-04-26 18:39:05 +0530916
917 kfree(pconfig);
Pierre-Louis Bossart57a34792019-09-16 14:23:46 -0500918error:
Vinod Koulc46302e2018-04-26 18:39:05 +0530919 return ret;
920}
921
Rander Wang27b198f2020-02-14 19:47:37 -0600922static int intel_prepare(struct snd_pcm_substream *substream,
923 struct snd_soc_dai *dai)
924{
925 struct sdw_cdns_dma_data *dma;
926
927 dma = snd_soc_dai_get_dma_data(dai, substream);
928 if (!dma) {
929 dev_err(dai->dev, "failed to get dma data in %s",
930 __func__);
931 return -EIO;
932 }
933
934 return sdw_prepare_stream(dma->stream);
935}
936
Rander Wang973a8422020-02-14 19:47:38 -0600937static int intel_trigger(struct snd_pcm_substream *substream, int cmd,
938 struct snd_soc_dai *dai)
939{
940 struct sdw_cdns_dma_data *dma;
941 int ret;
942
943 dma = snd_soc_dai_get_dma_data(dai, substream);
944 if (!dma) {
945 dev_err(dai->dev, "failed to get dma data in %s", __func__);
946 return -EIO;
947 }
948
949 switch (cmd) {
950 case SNDRV_PCM_TRIGGER_START:
951 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
952 case SNDRV_PCM_TRIGGER_RESUME:
953 ret = sdw_enable_stream(dma->stream);
954 break;
955
956 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
957 case SNDRV_PCM_TRIGGER_SUSPEND:
958 case SNDRV_PCM_TRIGGER_STOP:
959 ret = sdw_disable_stream(dma->stream);
960 break;
961
962 default:
963 ret = -EINVAL;
964 break;
965 }
966
967 if (ret)
968 dev_err(dai->dev,
969 "%s trigger %d failed: %d",
970 __func__, cmd, ret);
971 return ret;
972}
973
Vinod Koulc46302e2018-04-26 18:39:05 +0530974static int
975intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
976{
977 struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -0600978 struct sdw_intel *sdw = cdns_to_intel(cdns);
Vinod Koulc46302e2018-04-26 18:39:05 +0530979 struct sdw_cdns_dma_data *dma;
980 int ret;
981
982 dma = snd_soc_dai_get_dma_data(dai, substream);
983 if (!dma)
984 return -EIO;
985
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -0600986 ret = sdw_deprepare_stream(dma->stream);
987 if (ret) {
988 dev_err(dai->dev, "sdw_deprepare_stream: failed %d", ret);
989 return ret;
990 }
991
Vinod Koulc46302e2018-04-26 18:39:05 +0530992 ret = sdw_stream_remove_master(&cdns->bus, dma->stream);
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -0600993 if (ret < 0) {
Pierre-Louis Bossart17ed5be2019-05-01 10:57:45 -0500994 dev_err(dai->dev, "remove master from stream %s failed: %d\n",
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -0500995 dma->stream->name, ret);
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -0600996 return ret;
997 }
Vinod Koulc46302e2018-04-26 18:39:05 +0530998
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -0600999 ret = intel_free_stream(sdw, substream, dai, sdw->instance);
1000 if (ret < 0) {
1001 dev_err(dai->dev, "intel_free_stream: failed %d", ret);
1002 return ret;
1003 }
1004
Pierre-Louis Bossarteff346f2020-02-14 19:47:40 -06001005 return 0;
Vinod Koulc46302e2018-04-26 18:39:05 +05301006}
1007
Pierre-Louis Bossart183c7682019-08-05 19:55:22 -05001008static void intel_shutdown(struct snd_pcm_substream *substream,
1009 struct snd_soc_dai *dai)
1010{
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001011 struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
Pierre-Louis Bossart183c7682019-08-05 19:55:22 -05001012
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001013 pm_runtime_mark_last_busy(cdns->dev);
1014 pm_runtime_put_autosuspend(cdns->dev);
Pierre-Louis Bossart183c7682019-08-05 19:55:22 -05001015}
1016
Vinod Koulc46302e2018-04-26 18:39:05 +05301017static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -05001018 void *stream, int direction)
Vinod Koulc46302e2018-04-26 18:39:05 +05301019{
1020 return cdns_set_sdw_stream(dai, stream, true, direction);
1021}
1022
1023static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -05001024 void *stream, int direction)
Vinod Koulc46302e2018-04-26 18:39:05 +05301025{
1026 return cdns_set_sdw_stream(dai, stream, false, direction);
1027}
1028
Pierre-Louis Bossart09553142020-07-01 02:43:52 +08001029static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
1030 int direction)
1031{
1032 struct sdw_cdns_dma_data *dma;
1033
1034 if (direction == SNDRV_PCM_STREAM_PLAYBACK)
1035 dma = dai->playback_dma_data;
1036 else
1037 dma = dai->capture_dma_data;
1038
1039 if (!dma)
1040 return NULL;
1041
1042 return dma->stream;
1043}
1044
Julia Lawallb1635592018-10-27 15:34:42 +02001045static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
Rander Wang5e7484d2020-02-14 19:47:39 -06001046 .startup = intel_startup,
Vinod Koulc46302e2018-04-26 18:39:05 +05301047 .hw_params = intel_hw_params,
Rander Wang27b198f2020-02-14 19:47:37 -06001048 .prepare = intel_prepare,
Rander Wang973a8422020-02-14 19:47:38 -06001049 .trigger = intel_trigger,
Vinod Koulc46302e2018-04-26 18:39:05 +05301050 .hw_free = intel_hw_free,
Pierre-Louis Bossart183c7682019-08-05 19:55:22 -05001051 .shutdown = intel_shutdown,
Vinod Koulc46302e2018-04-26 18:39:05 +05301052 .set_sdw_stream = intel_pcm_set_sdw_stream,
Pierre-Louis Bossart09553142020-07-01 02:43:52 +08001053 .get_sdw_stream = intel_get_sdw_stream,
Vinod Koulc46302e2018-04-26 18:39:05 +05301054};
1055
Julia Lawallb1635592018-10-27 15:34:42 +02001056static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
Rander Wang5e7484d2020-02-14 19:47:39 -06001057 .startup = intel_startup,
Vinod Koulc46302e2018-04-26 18:39:05 +05301058 .hw_params = intel_hw_params,
Rander Wang27b198f2020-02-14 19:47:37 -06001059 .prepare = intel_prepare,
Rander Wang973a8422020-02-14 19:47:38 -06001060 .trigger = intel_trigger,
Vinod Koulc46302e2018-04-26 18:39:05 +05301061 .hw_free = intel_hw_free,
Pierre-Louis Bossart183c7682019-08-05 19:55:22 -05001062 .shutdown = intel_shutdown,
Vinod Koulc46302e2018-04-26 18:39:05 +05301063 .set_sdw_stream = intel_pdm_set_sdw_stream,
Pierre-Louis Bossart09553142020-07-01 02:43:52 +08001064 .get_sdw_stream = intel_get_sdw_stream,
Vinod Koulc46302e2018-04-26 18:39:05 +05301065};
1066
1067static const struct snd_soc_component_driver dai_component = {
1068 .name = "soundwire",
1069};
1070
1071static int intel_create_dai(struct sdw_cdns *cdns,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -05001072 struct snd_soc_dai_driver *dais,
1073 enum intel_pdi_type type,
1074 u32 num, u32 off, u32 max_ch, bool pcm)
Vinod Koulc46302e2018-04-26 18:39:05 +05301075{
1076 int i;
1077
1078 if (num == 0)
1079 return 0;
1080
1081 /* TODO: Read supported rates/formats from hardware */
1082 for (i = off; i < (off + num); i++) {
Pierre-Louis Bossartbf6d6e62020-06-17 11:35:36 -05001083 dais[i].name = devm_kasprintf(cdns->dev, GFP_KERNEL,
1084 "SDW%d Pin%d",
1085 cdns->instance, i);
Vinod Koulc46302e2018-04-26 18:39:05 +05301086 if (!dais[i].name)
1087 return -ENOMEM;
1088
1089 if (type == INTEL_PDI_BD || type == INTEL_PDI_OUT) {
Vinod Koulc46302e2018-04-26 18:39:05 +05301090 dais[i].playback.channels_min = 1;
1091 dais[i].playback.channels_max = max_ch;
1092 dais[i].playback.rates = SNDRV_PCM_RATE_48000;
1093 dais[i].playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
1094 }
1095
1096 if (type == INTEL_PDI_BD || type == INTEL_PDI_IN) {
Srinivas Kandagatla39194122019-06-06 12:23:04 +01001097 dais[i].capture.channels_min = 1;
1098 dais[i].capture.channels_max = max_ch;
Vinod Koulc46302e2018-04-26 18:39:05 +05301099 dais[i].capture.rates = SNDRV_PCM_RATE_48000;
1100 dais[i].capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
1101 }
1102
Vinod Koulc46302e2018-04-26 18:39:05 +05301103 if (pcm)
1104 dais[i].ops = &intel_pcm_dai_ops;
1105 else
1106 dais[i].ops = &intel_pdm_dai_ops;
1107 }
1108
1109 return 0;
1110}
1111
1112static int intel_register_dai(struct sdw_intel *sdw)
1113{
1114 struct sdw_cdns *cdns = &sdw->cdns;
1115 struct sdw_cdns_streams *stream;
1116 struct snd_soc_dai_driver *dais;
1117 int num_dai, ret, off = 0;
1118
1119 /* DAIs are created based on total number of PDIs supported */
1120 num_dai = cdns->pcm.num_pdi + cdns->pdm.num_pdi;
1121
1122 dais = devm_kcalloc(cdns->dev, num_dai, sizeof(*dais), GFP_KERNEL);
1123 if (!dais)
1124 return -ENOMEM;
1125
1126 /* Create PCM DAIs */
1127 stream = &cdns->pcm;
1128
Bard Liaocf924962019-09-16 14:23:43 -05001129 ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pcm.num_in,
Vinod Koul1215dae2019-05-02 16:29:25 +05301130 off, stream->num_ch_in, true);
Vinod Koulc46302e2018-04-26 18:39:05 +05301131 if (ret)
1132 return ret;
1133
1134 off += cdns->pcm.num_in;
Vinod Koul1215dae2019-05-02 16:29:25 +05301135 ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pcm.num_out,
1136 off, stream->num_ch_out, true);
Vinod Koulc46302e2018-04-26 18:39:05 +05301137 if (ret)
1138 return ret;
1139
1140 off += cdns->pcm.num_out;
Vinod Koul1215dae2019-05-02 16:29:25 +05301141 ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pcm.num_bd,
1142 off, stream->num_ch_bd, true);
Vinod Koulc46302e2018-04-26 18:39:05 +05301143 if (ret)
1144 return ret;
1145
1146 /* Create PDM DAIs */
1147 stream = &cdns->pdm;
1148 off += cdns->pcm.num_bd;
Vinod Koul1215dae2019-05-02 16:29:25 +05301149 ret = intel_create_dai(cdns, dais, INTEL_PDI_IN, cdns->pdm.num_in,
1150 off, stream->num_ch_in, false);
Vinod Koulc46302e2018-04-26 18:39:05 +05301151 if (ret)
1152 return ret;
1153
1154 off += cdns->pdm.num_in;
Vinod Koul1215dae2019-05-02 16:29:25 +05301155 ret = intel_create_dai(cdns, dais, INTEL_PDI_OUT, cdns->pdm.num_out,
1156 off, stream->num_ch_out, false);
Vinod Koulc46302e2018-04-26 18:39:05 +05301157 if (ret)
1158 return ret;
1159
Bard Liaocf924962019-09-16 14:23:43 -05001160 off += cdns->pdm.num_out;
Vinod Koul1215dae2019-05-02 16:29:25 +05301161 ret = intel_create_dai(cdns, dais, INTEL_PDI_BD, cdns->pdm.num_bd,
1162 off, stream->num_ch_bd, false);
Vinod Koulc46302e2018-04-26 18:39:05 +05301163 if (ret)
1164 return ret;
1165
1166 return snd_soc_register_component(cdns->dev, &dai_component,
Pierre-Louis Bossartd542bc92019-05-01 10:57:38 -05001167 dais, num_dai);
Vinod Koulc46302e2018-04-26 18:39:05 +05301168}
1169
Pierre-Louis Bossart085f4ac2019-08-05 19:55:16 -05001170static int sdw_master_read_intel_prop(struct sdw_bus *bus)
1171{
1172 struct sdw_master_prop *prop = &bus->prop;
1173 struct fwnode_handle *link;
1174 char name[32];
Pierre-Louis Bossart395713d2019-08-21 13:58:21 -05001175 u32 quirk_mask;
Pierre-Louis Bossart085f4ac2019-08-05 19:55:16 -05001176
1177 /* Find master handle */
1178 snprintf(name, sizeof(name),
1179 "mipi-sdw-link-%d-subproperties", bus->link_id);
1180
1181 link = device_get_named_child_node(bus->dev, name);
1182 if (!link) {
1183 dev_err(bus->dev, "Master node %s not found\n", name);
1184 return -EIO;
1185 }
1186
1187 fwnode_property_read_u32(link,
1188 "intel-sdw-ip-clock",
1189 &prop->mclk_freq);
Pierre-Louis Bossart395713d2019-08-21 13:58:21 -05001190
Bard Liaoa19efb52020-01-13 17:11:29 -06001191 /* the values reported by BIOS are the 2x clock, not the bus clock */
1192 prop->mclk_freq /= 2;
1193
Pierre-Louis Bossart395713d2019-08-21 13:58:21 -05001194 fwnode_property_read_u32(link,
1195 "intel-quirk-mask",
1196 &quirk_mask);
1197
1198 if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
1199 prop->hw_disabled = true;
1200
Pierre-Louis Bossart085f4ac2019-08-05 19:55:16 -05001201 return 0;
1202}
1203
Vinod Koul71bb8a12017-12-14 11:19:43 +05301204static int intel_prop_read(struct sdw_bus *bus)
1205{
1206 /* Initialize with default handler to read all DisCo properties */
1207 sdw_master_read_prop(bus);
1208
Pierre-Louis Bossart085f4ac2019-08-05 19:55:16 -05001209 /* read Intel-specific properties */
1210 sdw_master_read_intel_prop(bus);
1211
Vinod Koul71bb8a12017-12-14 11:19:43 +05301212 return 0;
1213}
1214
Shreyas NCc91605f2018-04-26 18:38:43 +05301215static struct sdw_master_ops sdw_intel_ops = {
1216 .read_prop = sdw_master_read_prop,
1217 .xfer_msg = cdns_xfer_msg,
1218 .xfer_msg_defer = cdns_xfer_msg_defer,
1219 .reset_page_addr = cdns_reset_page_addr,
Vinod Koul07abeff2018-04-26 18:38:48 +05301220 .set_bus_conf = cdns_bus_conf,
Shreyas NC30246e22018-07-27 14:44:17 +05301221 .pre_bank_switch = intel_pre_bank_switch,
1222 .post_bank_switch = intel_post_bank_switch,
Shreyas NCc91605f2018-04-26 18:38:43 +05301223};
1224
Pierre-Louis Bossartdfbe6422019-10-22 18:54:46 -05001225static int intel_init(struct sdw_intel *sdw)
1226{
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +08001227 bool clock_stop;
1228
Pierre-Louis Bossartdfbe6422019-10-22 18:54:46 -05001229 /* Initialize shim and controller */
1230 intel_link_power_up(sdw);
Pierre-Louis Bossart4a17c442020-07-16 23:09:40 +08001231
1232 clock_stop = sdw_cdns_is_clock_stop(&sdw->cdns);
1233
1234 intel_shim_init(sdw, clock_stop);
1235
1236 if (clock_stop)
1237 return 0;
Pierre-Louis Bossartdfbe6422019-10-22 18:54:46 -05001238
Rander Wang7b174f22020-03-17 11:33:14 -05001239 return sdw_cdns_init(&sdw->cdns);
Pierre-Louis Bossartdfbe6422019-10-22 18:54:46 -05001240}
1241
Vinod Koul71bb8a12017-12-14 11:19:43 +05301242/*
1243 * probe and init
1244 */
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001245static int intel_master_probe(struct platform_device *pdev)
Vinod Koul71bb8a12017-12-14 11:19:43 +05301246{
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001247 struct device *dev = &pdev->dev;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301248 struct sdw_intel *sdw;
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001249 struct sdw_cdns *cdns;
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001250 struct sdw_bus *bus;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301251 int ret;
1252
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001253 sdw = devm_kzalloc(dev, sizeof(*sdw), GFP_KERNEL);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301254 if (!sdw)
1255 return -ENOMEM;
1256
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001257 cdns = &sdw->cdns;
1258 bus = &cdns->bus;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301259
Vinod Koul71bb8a12017-12-14 11:19:43 +05301260 sdw->instance = pdev->id;
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001261 sdw->link_res = dev_get_platdata(dev);
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001262 cdns->dev = dev;
1263 cdns->registers = sdw->link_res->registers;
1264 cdns->instance = sdw->instance;
1265 cdns->msg_count = 0;
1266
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001267 bus->link_id = pdev->id;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301268
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001269 sdw_cdns_probe(cdns);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301270
1271 /* Set property read ops */
Shreyas NCc91605f2018-04-26 18:38:43 +05301272 sdw_intel_ops.read_prop = intel_prop_read;
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001273 bus->ops = &sdw_intel_ops;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301274
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001275 /* set driver data, accessed by snd_soc_dai_get_drvdata() */
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001276 dev_set_drvdata(dev, cdns);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301277
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001278 ret = sdw_bus_master_add(bus, dev, dev->fwnode);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301279 if (ret) {
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001280 dev_err(dev, "sdw_bus_master_add fail: %d\n", ret);
Pierre-Louis Bossart9e3d47f2019-10-22 18:54:47 -05001281 return ret;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301282 }
1283
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001284 if (bus->prop.hw_disabled)
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001285 dev_info(dev,
1286 "SoundWire master %d is disabled, will be ignored\n",
1287 bus->link_id);
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001288
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001289 return 0;
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001290}
1291
1292int intel_master_startup(struct platform_device *pdev)
1293{
1294 struct sdw_cdns_stream_config config;
1295 struct device *dev = &pdev->dev;
1296 struct sdw_cdns *cdns = dev_get_drvdata(dev);
1297 struct sdw_intel *sdw = cdns_to_intel(cdns);
1298 struct sdw_bus *bus = &cdns->bus;
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001299 int link_flags;
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001300 int ret;
1301
1302 if (bus->prop.hw_disabled) {
1303 dev_info(dev,
1304 "SoundWire master %d is disabled, ignoring\n",
1305 sdw->instance);
Pierre-Louis Bossart395713d2019-08-21 13:58:21 -05001306 return 0;
1307 }
1308
Pierre-Louis Bossartdfbe6422019-10-22 18:54:46 -05001309 /* Initialize shim, controller and Cadence IP */
1310 ret = intel_init(sdw);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301311 if (ret)
1312 goto err_init;
1313
Vinod Koul37a2d222018-04-26 18:38:58 +05301314 /* Read the PDI config and initialize cadence PDI */
1315 intel_pdi_init(sdw, &config);
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001316 ret = sdw_cdns_pdi_init(cdns, config);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301317 if (ret)
1318 goto err_init;
1319
Vinod Koul37a2d222018-04-26 18:38:58 +05301320 intel_pdi_ch_update(sdw);
1321
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001322 ret = sdw_cdns_enable_interrupt(cdns, true);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301323 if (ret < 0) {
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001324 dev_err(dev, "cannot enable interrupts\n");
Vinod Koul71bb8a12017-12-14 11:19:43 +05301325 goto err_init;
1326 }
1327
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001328 ret = sdw_cdns_exit_reset(cdns);
Pierre-Louis Bossart49ea07d2019-10-22 18:54:44 -05001329 if (ret < 0) {
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001330 dev_err(dev, "unable to exit bus reset sequence\n");
Pierre-Louis Bossart9e3d47f2019-10-22 18:54:47 -05001331 goto err_interrupt;
Pierre-Louis Bossart49ea07d2019-10-22 18:54:44 -05001332 }
1333
Vinod Koulc46302e2018-04-26 18:39:05 +05301334 /* Register DAIs */
1335 ret = intel_register_dai(sdw);
1336 if (ret) {
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001337 dev_err(dev, "DAI registration failed: %d\n", ret);
1338 snd_soc_unregister_component(dev);
Pierre-Louis Bossart9e3d47f2019-10-22 18:54:47 -05001339 goto err_interrupt;
Vinod Koulc46302e2018-04-26 18:39:05 +05301340 }
1341
Pierre-Louis Bossart79ee6632019-08-21 13:58:20 -05001342 intel_debugfs_init(sdw);
1343
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001344 /* Enable runtime PM */
1345 link_flags = md_flags >> (bus->link_id * 8);
1346 if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME)) {
1347 pm_runtime_set_autosuspend_delay(dev,
1348 INTEL_MASTER_SUSPEND_DELAY_MS);
1349 pm_runtime_use_autosuspend(dev);
1350 pm_runtime_mark_last_busy(dev);
1351
1352 pm_runtime_set_active(dev);
1353 pm_runtime_enable(dev);
1354 }
1355
Vinod Koul71bb8a12017-12-14 11:19:43 +05301356 return 0;
1357
Pierre-Louis Bossart9e3d47f2019-10-22 18:54:47 -05001358err_interrupt:
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001359 sdw_cdns_enable_interrupt(cdns, false);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301360err_init:
Vinod Koul71bb8a12017-12-14 11:19:43 +05301361 return ret;
1362}
1363
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001364static int intel_master_remove(struct platform_device *pdev)
Vinod Koul71bb8a12017-12-14 11:19:43 +05301365{
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001366 struct device *dev = &pdev->dev;
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001367 struct sdw_cdns *cdns = dev_get_drvdata(dev);
1368 struct sdw_intel *sdw = cdns_to_intel(cdns);
1369 struct sdw_bus *bus = &cdns->bus;
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001370
1371 if (!bus->prop.hw_disabled) {
Pierre-Louis Bossart395713d2019-08-21 13:58:21 -05001372 intel_debugfs_exit(sdw);
Pierre-Louis Bossart83e129af2020-06-01 02:20:58 +08001373 sdw_cdns_enable_interrupt(cdns, false);
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001374 snd_soc_unregister_component(dev);
Pierre-Louis Bossart395713d2019-08-21 13:58:21 -05001375 }
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001376 sdw_bus_master_delete(bus);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301377
1378 return 0;
1379}
1380
Rander Wangab2c9132020-07-16 23:09:46 +08001381int intel_master_process_wakeen_event(struct platform_device *pdev)
1382{
1383 struct device *dev = &pdev->dev;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301384 struct sdw_intel *sdw;
Rander Wangab2c9132020-07-16 23:09:46 +08001385 struct sdw_bus *bus;
1386 void __iomem *shim;
1387 u16 wake_sts;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301388
1389 sdw = platform_get_drvdata(pdev);
Rander Wangab2c9132020-07-16 23:09:46 +08001390 bus = &sdw->cdns.bus;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301391
Rander Wangab2c9132020-07-16 23:09:46 +08001392 if (bus->prop.hw_disabled) {
1393 dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id);
1394 return 0;
Vinod Koul71bb8a12017-12-14 11:19:43 +05301395 }
Rander Wangab2c9132020-07-16 23:09:46 +08001396
1397 shim = sdw->link_res->shim;
1398 wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
1399
1400 if (!(wake_sts & BIT(sdw->instance)))
1401 return 0;
1402
1403 /* disable WAKEEN interrupt ASAP to prevent interrupt flood */
1404 intel_shim_wake(sdw, false);
1405
1406 /*
1407 * resume the Master, which will generate a bus reset and result in
1408 * Slaves re-attaching and be re-enumerated. The SoundWire physical
1409 * device which generated the wake will trigger an interrupt, which
1410 * will in turn cause the corresponding Linux Slave device to be
1411 * resumed and the Slave codec driver to check the status.
1412 */
1413 pm_request_resume(dev);
Vinod Koul71bb8a12017-12-14 11:19:43 +05301414
1415 return 0;
1416}
1417
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001418/*
1419 * PM calls
1420 */
1421
1422#ifdef CONFIG_PM
1423
1424static int intel_suspend(struct device *dev)
1425{
1426 struct sdw_cdns *cdns = dev_get_drvdata(dev);
1427 struct sdw_intel *sdw = cdns_to_intel(cdns);
1428 struct sdw_bus *bus = &cdns->bus;
1429 int ret;
1430
1431 if (bus->prop.hw_disabled) {
1432 dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1433 bus->link_id);
1434 return 0;
1435 }
1436
Pierre-Louis Bossartb61b8b32020-08-17 23:29:13 +08001437 if (pm_runtime_suspended(dev)) {
1438 dev_dbg(dev, "%s: pm_runtime status: suspended\n", __func__);
1439
1440 return 0;
1441 }
1442
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001443 ret = sdw_cdns_enable_interrupt(cdns, false);
1444 if (ret < 0) {
1445 dev_err(dev, "cannot disable interrupts on suspend\n");
1446 return ret;
1447 }
1448
1449 ret = intel_link_power_down(sdw);
1450 if (ret) {
1451 dev_err(dev, "Link power down failed: %d", ret);
1452 return ret;
1453 }
1454
1455 intel_shim_wake(sdw, false);
1456
1457 return 0;
1458}
1459
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001460static int intel_suspend_runtime(struct device *dev)
1461{
1462 struct sdw_cdns *cdns = dev_get_drvdata(dev);
1463 struct sdw_intel *sdw = cdns_to_intel(cdns);
1464 struct sdw_bus *bus = &cdns->bus;
1465 int ret;
1466
1467 if (bus->prop.hw_disabled) {
1468 dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1469 bus->link_id);
1470 return 0;
1471 }
1472
1473 ret = sdw_cdns_enable_interrupt(cdns, false);
1474 if (ret < 0) {
1475 dev_err(dev, "cannot disable interrupts on suspend\n");
1476 return ret;
1477 }
1478
1479 ret = intel_link_power_down(sdw);
1480 if (ret) {
1481 dev_err(dev, "Link power down failed: %d", ret);
1482 return ret;
1483 }
1484
1485 intel_shim_wake(sdw, false);
1486
1487 return 0;
1488}
1489
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001490static int intel_resume(struct device *dev)
1491{
1492 struct sdw_cdns *cdns = dev_get_drvdata(dev);
1493 struct sdw_intel *sdw = cdns_to_intel(cdns);
1494 struct sdw_bus *bus = &cdns->bus;
1495 int ret;
1496
1497 if (bus->prop.hw_disabled) {
1498 dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1499 bus->link_id);
1500 return 0;
1501 }
1502
Pierre-Louis Bossartb61b8b32020-08-17 23:29:13 +08001503 if (pm_runtime_suspended(dev)) {
1504 dev_dbg(dev, "%s: pm_runtime status was suspended, forcing active\n", __func__);
1505
1506 /* follow required sequence from runtime_pm.rst */
1507 pm_runtime_disable(dev);
1508 pm_runtime_set_active(dev);
1509 pm_runtime_mark_last_busy(dev);
1510 pm_runtime_enable(dev);
1511 }
1512
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001513 ret = intel_init(sdw);
1514 if (ret) {
1515 dev_err(dev, "%s failed: %d", __func__, ret);
1516 return ret;
1517 }
1518
1519 ret = sdw_cdns_enable_interrupt(cdns, true);
1520 if (ret < 0) {
1521 dev_err(dev, "cannot enable interrupts during resume\n");
1522 return ret;
1523 }
1524
1525 ret = sdw_cdns_exit_reset(cdns);
1526 if (ret < 0) {
1527 dev_err(dev, "unable to exit bus reset sequence during resume\n");
1528 return ret;
1529 }
1530
1531 return ret;
1532}
1533
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001534static int intel_resume_runtime(struct device *dev)
1535{
1536 struct sdw_cdns *cdns = dev_get_drvdata(dev);
1537 struct sdw_intel *sdw = cdns_to_intel(cdns);
1538 struct sdw_bus *bus = &cdns->bus;
1539 int ret;
1540
1541 if (bus->prop.hw_disabled) {
1542 dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
1543 bus->link_id);
1544 return 0;
1545 }
1546
1547 ret = intel_init(sdw);
1548 if (ret) {
1549 dev_err(dev, "%s failed: %d", __func__, ret);
1550 return ret;
1551 }
1552
1553 ret = sdw_cdns_enable_interrupt(cdns, true);
1554 if (ret < 0) {
1555 dev_err(dev, "cannot enable interrupts during resume\n");
1556 return ret;
1557 }
1558
1559 ret = sdw_cdns_exit_reset(cdns);
1560 if (ret < 0) {
1561 dev_err(dev, "unable to exit bus reset sequence during resume\n");
1562 return ret;
1563 }
1564
1565 return ret;
1566}
1567
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001568#endif
1569
1570static const struct dev_pm_ops intel_pm = {
1571 SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
Pierre-Louis Bossartebf878e2020-08-17 23:29:12 +08001572 SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL)
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001573};
1574
Vinod Koul71bb8a12017-12-14 11:19:43 +05301575static struct platform_driver sdw_intel_drv = {
Pierre-Louis Bossartb6109dd2020-06-01 02:20:57 +08001576 .probe = intel_master_probe,
1577 .remove = intel_master_remove,
Vinod Koul71bb8a12017-12-14 11:19:43 +05301578 .driver = {
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001579 .name = "intel-sdw",
Pierre-Louis Bossart9b3b4b32020-07-22 04:37:11 +08001580 .pm = &intel_pm,
1581 }
Vinod Koul71bb8a12017-12-14 11:19:43 +05301582};
1583
1584module_platform_driver(sdw_intel_drv);
1585
1586MODULE_LICENSE("Dual BSD/GPL");
Pierre-Louis Bossart6d2c6662020-06-01 02:21:02 +08001587MODULE_ALIAS("platform:intel-sdw");
Vinod Koul71bb8a12017-12-14 11:19:43 +05301588MODULE_DESCRIPTION("Intel Soundwire Master Driver");