aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/intel_mid_i2s/intel_mid_i2s.h
blob: 819164d9d93b0b0b9ccd8e76b30233143a73d8a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
/*
  * <Driver for I2S protocol on SSP (Moorestown and Medfield hardware)>
  * Copyright (c) 2010, Intel Corporation.
  * Louis LE GALL <louis.le.gall intel.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
  *
  * This program is distributed in the hope it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  * more details.
  *
  * You should have received a copy of the GNU General Public License along with
  * this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
#define DRIVER_NAME "I2S SSP Driver"
/*
 * Defines
 */
#define MFLD_SSP1_DEVICE_ID 0x0825	/* FOR MFLD */
#define MRST_SSP0_DEVICE_ID 0x0815	/* FOR MRST */
#define MFLD_SSP0_DEVICE_ID 0x0832	/* FOR MFLD */

#define MRST_LPE_DMA_DEVICE_ID 0x0814
#define MFLD_LPE_DMA_DEVICE_ID 0x0830

/* SSP1 PCI device Base Address Register */
#define MRST_SSP_BAR	0
#define MRST_LPE_BAR	1
#define DMA1C_DEVICE_INSTANCE_SSP0 0
#define DMA1C_DEVICE_INSTANCE_SSP1 1
#define OFFSET_SSCR0	0x00
#define OFFSET_SSCR1	0x04
#define OFFSET_SSSR		0x08
#define OFFSET_SSITR	0x0c
#define OFFSET_SSDR		0x10
#define OFFSET_SSTO		0x28
#define OFFSET_SSPSP	0x2c
#define OFFSET_SSTSA	0x30	/* SSP Tx Timeslot Active */
#define OFFSET_SSRSA	0x34	/* SSP Rx Timeslot Active */
/* SST register map */
#define OFFSET_LPE_CSR			0x00
#define OFFSET_LPE_PISR			0x08
#define OFFSET_LPE_PIMR			0x10
#define OFFSET_LPE_ISRX			0x18
#define OFFSET_LPE_IMRX			0x28
#define OFFSET_LPE_IPCX			0x38	/* IPC IA-SST */
#define OFFSET_LPE_IPCD			0x40	/* IPC SST-IA */
#define OFFSET_LPE_ISRD			0x20	/* dummy register for*/
						/* shim workaround   */
#define OFFSET_LPE_SHIM_SIZE	0X44

#define SSP_IN_MASTER_MODE		0x0
#define SSP_IN_SLAVE_MODE		0x1

/*
 *	Macros
 */
#define DEFINE_SSP_REG(reg, off) \
static inline u32 read_##reg(void *p) { return __raw_readl(p + (off)); } \
static inline void write_##reg(u32 v, void *p) { __raw_writel(v, p + (off)); }
DEFINE_SSP_REG(SSCR0, 0x00)
DEFINE_SSP_REG(SSCR1, 0x04)
DEFINE_SSP_REG(SSSR, 0x08)
DEFINE_SSP_REG(SSITR, 0x0c)
DEFINE_SSP_REG(SSDR, 0x10)
DEFINE_SSP_REG(SSTO, 0x28)
DEFINE_SSP_REG(SSPSP, 0x2c)
DEFINE_SSP_REG(SSTSA, 0x30)
DEFINE_SSP_REG(SSRSA, 0x34)
DEFINE_SSP_REG(SSTSS, 0x38)
DEFINE_SSP_REG(SSACD, 0x3C)
DEFINE_SSP_REG(I2CCTRL, 0x00);
DEFINE_SSP_REG(I2CDATA, 0x04);
/*
 * Langwell SSP serial port register definitions
 */
#define SSCR0_DSS_MASK   0x0F	/* Data Size Select [4..16] */
#define SSCR0_DSS_SHIFT  0
#define SSCR0_FRF_MASK   0x03	/* FRame Format */
#define SSCR0_FRF_SHIFT  4
#define SSCR0_ECS_MASK   0x01	/* External clock select */
#define SSCR0_ECS_SHIFT  6
#define SSCR0_SSE_MASK   0x01	/* Synchronous Serial Port Enable */
#define SSCR0_SSE_SHIFT  7
#define SSCR0_SCR_MASK   0xFFF	/* Not implemented */
#define SSCR0_SCR_SHIFT  8
#define SSCR0_EDSS_MASK  0x1	/* Extended data size select */
#define SSCR0_EDSS_SHIFT 20
#define SSCR0_NCS_MASK   0x1	/* Network clock select */
#define SSCR0_NCS_SHIFT  21
#define SSCR0_RIM_MASK   0x1	/* Receive FIFO overrrun int mask */
#define SSCR0_RIM_SHIFT  22
#define SSCR0_TIM_MASK   0x1	/* Transmit FIFO underrun int mask */
#define SSCR0_TIM_SHIFT  23
#define SSCR0_FRDC_MASK  0x7	/* Frame Rate Divider Control */
#define SSCR0_FRDC_SHIFT 24
#define SSCR0_ACS_MASK   0x1	/* Audio clock select */
#define SSCR0_ACS_SHIFT  30
#define SSCR0_MOD_MASK   0x1	/* Mode (normal or network) */
#define SSCR0_MOD_SHIFT  31

#define SSCR0_DataSize(x)     ((x) - 1)	/* Data Size Select [4..16] */
#define SSCR0_SlotsPerFrm(x)  ((x) - 1)	/* Time slots per frame */
#define SSCR0_SerClkDiv(x)    ((x) - 1)	/* Divisor [1..4096],... */
					 /*...not implemented on Langwell */
#define SSCR1_TTELP_MASK     0x1	/* TXD Tristate Enable on Last Phase */
#define SSCR1_TTELP_SHIFT    31
#define SSCR1_TTE_MASK	     0x1	/* TXD Tristate Enable */
#define SSCR1_TTE_SHIFT      30
#define SSCR1_EBCEI_MASK     0x1	/* Enable Bit Count Error Interrupt */
#define SSCR1_EBCEI_SHIFT    29
#define SSCR1_SCFR_MASK      0x1	/* Slave Clock Running */
#define SSCR1_SCFR_SHIFT     28
#define SSCR1_ECRA_MASK      0x1	/* Enable Clock Request A */
#define SSCR1_ECRA_SHIFT     27
#define SSCR1_ECRB_MASK      0x1	/* Enable Clock Request B */
#define SSCR1_ECRB_SHIFT     26
#define SSCR1_SCLKDIR_MASK   0x1	/* SSPCLK Direction */
#define SSCR1_SCLKDIR_SHIFT  25
#define SSCR1_SFRMDIR_MASK   0x1	/* SSPFRM Direction */
#define SSCR1_SFRMDIR_SHIFT  24
#define SSCR1_RWOT_MASK      0x1	/* Receive without Transmit */
#define SSCR1_RWOT_SHIFT     23
#define SSCR1_TRAIL_MASK     0x1	/* Trailing Byte */
#define SSCR1_TRAIL_SHIFT    22
#define SSCR1_TSRE_MASK      0x1	/* DMA Transmit Service Request Enable*/
#define SSCR1_TSRE_SHIFT     21
#define SSCR1_RSRE_MASK      0x1	/* DMA Receive Service Request Enable */
#define SSCR1_RSRE_SHIFT     20
#define SSCR1_TINTE_MASK     0x1	/* Receiver Time-out Interrupt Enable */
#define SSCR1_TINTE_SHIFT    19
#define SSCR1_PINTE_MASK     0x1	/* Periph. Trailing Byte Int. Enable */
#define SSCR1_PINTE_SHIFT    18
#define SSCR1_IFS_MASK       0x1	/* Invert Frame Signal */
#define SSCR1_IFS_SHIFT      16
#define SSCR1_STFR_MASK      0x1	/* Select FIFO for EFWR: test mode */
#define SSCR1_STFR_SHIFT     15
#define SSCR1_EFWR_MASK      0x1	/* Enable FIFO Write/Read: test mode */
#define SSCR1_EFWR_SHIFT     14
#define SSCR1_RFT_MASK       0xF	/* Receive FIFO Trigger Threshold */
#define SSCR1_RFT_SHIFT      10
#define SSCR1_TFT_MASK       0xF	/* Transmit FIFO Trigger Threshold */
#define SSCR1_TFT_SHIFT      6
#define SSCR1_MWDS_MASK      0x1	/* Microwire Transmit Data Size */
#define SSCR1_MWDS_SHIFT     5
#define SSCR1_SPH_MASK       0x1	/* Motorola SPI SSPSCLK phase setting */
#define SSCR1_SPH_SHIFT      4
#define SSCR1_SPO_MASK       0x1	/* Motorola SPI SSPSCLK polarity */
#define SSCR1_SPO_SHIFT      3
#define SSCR1_LBM_MASK       0x1	/* Loopback mode: test mode */
#define SSCR1_LBM_SHIFT      2
#define SSCR1_TIE_MASK       0x1	/* Transmit FIFO Interrupt Enable */
#define SSCR1_TIE_SHIFT      1
#define SSCR1_RIE_MASK       0x1	/* Receive FIFO Interrupt Enable */
#define SSCR1_RIE_SHIFT      0

#define SSCR1_RxTresh(x) ((x) - 1)	/* level [1..16] */
#define SSCR1_TxTresh(x) ((x) - 1)	/* level [1..16] */

#define SSPSP_FSRT_MASK      0x1	/* Frame Sync Relative Timing Bit */
#define SSPSP_FSRT_SHIFT     25
#define SSPSP_DMYSTOP_MASK   0x3	/* Dummy Stop in Number of SSPSCLKs:T4*/
#define SSPSP_DMYSTOP_SHIFT  23
#define SSPSP_SFRMWDTH_MASK  0x3F	/* Serial Frame width : T6 */
#define SSPSP_SFRMWDTH_SHIFT 16
#define SSPSP_SFRMDLY_MASK   0x7F	/* Serial Fr. Delay in 1/2SSPSCLKs:T5 */
#define SSPSP_SFRMDLY_SHIFT  9
#define SSPSP_DMYSTRT_MASK   0x3	/* Dummy Start in Number of SSPSCLKs..*/
#define SSPSP_DMYSTRT_SHIFT  7	    /*...after STRTDLY, T2 (master mode only) */
#define SSPSP_STRTDLY_MASK   0x7	/* Start Delay, T1 (master mode only) */
#define SSPSP_STRTDLY_SHIFT  4
#define SSPSP_ETDS_MASK      0x1	/* End of Transfer Data State */
#define SSPSP_ETDS_SHIFT     3
#define SSPSP_SFRMP_MASK     0x1	/* Serial Frame Polarity */
#define SSPSP_SFRMP_SHIFT    2
#define SSPSP_SCMODE_MASK    0x3	/* Serial bit-rate Clock Mode */
#define SSPSP_SCMODE_SHIFT   0

#define SSTSA_TTSA_MASK      0xFF
#define SSTSA_TTSA_SHIFT     0

#define SSRSA_RTSA_MASK      0xFF
#define SSRSA_RTSA_SHIFT     0

#define SSSR_BCE_MASK   0x1	/* Bit Count Error: Read/Write 1 to Clear */
#define SSSR_BCE_SHIFT  23
#define SSSR_CSS_MASK   0x1	/* Clock Synchronization Status */
#define SSSR_CSS_SHIFT  22
#define SSSR_TUR_MASK   0x1	/* Transmit FIFO UnderRun: Rd/Wr 1 to Clear */
#define SSSR_TUR_SHIFT  21
#define SSSR_EOC_MASK   0x1	/* End Of Chain: Read/Write 1 to Clear */
#define SSSR_EOC_SHIFT  20
#define SSSR_TINT_MASK  0x1	/* Receiver Time-out Interrupt:... */
#define SSSR_TINT_SHIFT 19	/* ...Read/Write 1 to Clear */
#define SSSR_PINT_MASK  0x1	/* Peripheral Trailing Byte Interrupt:... */
#define SSSR_PINT_SHIFT 18	/* ...Read/Write 1 to Clear */
#define SSSR_RFL_MASK   0xF	/* Receive FIFO Level */
#define SSSR_RFL_SHIFT  12
#define SSSR_TFL_MASK   0xF	/* Transmit FIFO Level */
#define SSSR_TFL_SHIFT  8
#define SSSR_ROR_MASK   0x1	/* Receive FIFO Overrun: Read/Write 1 to Clear*/
#define SSSR_ROR_SHIFT  7
#define SSSR_RFS_MASK   0x1	/* Receive FIFO Service Request */
#define SSSR_RFS_SHIFT  6
#define SSSR_TFS_MASK   0x1	/* Transmit FIFO Service Request */
#define SSSR_TFS_SHIFT  5
#define SSSR_BSY_MASK   0x1	/* SSP Busy */
#define SSSR_BSY_SHIFT  4
#define SSSR_RNE_MASK   0x1	/* Receive FIFO not empty */
#define SSSR_RNE_SHIFT  3
#define SSSR_TFN_MASK   0x1	/* Transmit FIFO not Full */
#define SSSR_TFN_SHIFT  2


#define SSP_OFF 0
#define SSP_ON  1

/* bit I2S_PORT_OPENED lock for open/close
 * bit I2S_PORT_READ_BUSY lock for read requests (serialized)
 * bit I2S_PORT_WRITE_BUSY lock for write requests (serialized)
 * bit I2S_PORT_CLOSING means close on going, waiting for pending callbacks.
 */

enum i2s_flags {
	I2S_PORT_OPENED,
	I2S_PORT_WRITE_BUSY,
	I2S_PORT_READ_BUSY,
	I2S_PORT_CLOSING
};

#define FIFO_SIZE 16
/*
 *	Structures Definition
 */

/**
 * struct intel_mid_i2s_data - context struct to keep SSP I2S data
 * @pdev: pci dev pointer corresponding to context
 * @paddr:
 * @ioaddr:
 * @iolen:
 * @irq:
 * @clear_sr:
 * @mask_sr:
 * @dmac1:
 * @dmas_tx: dma slave structure for transmit
 * @dmas_rx: dma slave structure for receive
 * @txchan: Dma channel for transmit
 * @rxchan: Dma channel for receive
 *
 * @read_done:
 * @read_dst:
 * @read_len:
 *
 * @write_done:
 * @write_src:
 * @write_len:
 *
 * @mutex:  a mutex to make sure we have once-at-time critical functions.
 *
 * Longer description
 */

/* Locking rules:
 *
 * All the fields, not listed below, are set during probe, and then read only
 * So they do not require locking
 *
 * The fields that require locking are related to the I2S read and write
 * requests.
 *
 * We allow only 1 read at a time, and 1 write at a time.
 * We allow read in parallel of write but use separate variables.
 * We allow only 1 user per SSP/I2S port.
 * Typically this user will be a dedicated PulseAudio RT thread communicating
 * with cmt-speech driver which in turns communicates with intel_mid_ssp
 * driver.
 * PCM mixing is done before access to kernel drivers;typically within
 * PulseAudio or after; typically within the modem.
 * So no concurrent users, per I2S channel, to this driver are allowed
 * The read & write are triggered from a USER context
 * The read & write callbacks are called from a BH context
 * You should have not callback pending before calling close, close will wait
 * for remaining callback calls.
 * It is not allowed to call close function from read/write callback threads.
 *
 * Locking is handled via drv_data->flags & atomic bitwise operations
 *
 * I2S0 is dedicated for PCM transfer to/from the modem module
 * I2S1 is dedicated for PCM transfer to/from the Bluetooth or FM module
 *
 * read_done:
 * read_len:
 * read_dst:
 *
 * write_done:
 * write_src:
 * write_len:
 *
 * mutex:  a mutex to make sure we have once-at-time critical functions.
 *		once-at-a-time actions functions are:
 *			-intel_mid_i2s_open
 *			-intel_mid_i2s_close
 *			-intel_mid_i2s_rd_req
 *			-intel_mid_i2s_wr_req
 *			-intel_mid_i2s_set_rd_cb
 *			-intel_mid_i2s_set_wr_cb
 * These functions should not be called during a lock() neither in interrupt.
 */

struct intel_mid_i2s_hdl {
	/* Driver model hookup */
	struct pci_dev *pdev;
	/* register addresses */
	dma_addr_t paddr;
	void __iomem *ioaddr;
	u32 iolen;
	int irq;

	/* SSP masks */
	u32 clear_sr;
	u32 mask_sr;

	/* SSP Configuration */
	/* DMA info */
	struct pci_dev *dmac1;
	wait_queue_head_t wq_chan_closing;

	struct intel_mid_dma_slave dmas_tx;
	struct intel_mid_dma_slave dmas_rx;
	struct dma_chan *txchan;
	struct dma_chan *rxchan;

	unsigned int device_instance;
	/* Call back functions */
	int (*read_callback)(void *param);
	dma_addr_t read_dst;
	size_t read_len;     /* read_len > 0 <=> read_dma_running */
	void *read_param;	 /* context param for callback */
	int (*write_callback)(void *param);
	dma_addr_t write_src;
	size_t write_len;	/* write_len > 0 <=> read_dma_running */
	void *write_param;	/* context param for callback */

	unsigned long flags;
	struct mutex mutex;
	enum intel_mid_i2s_ssp_usage usage;

	struct intel_mid_i2s_settings current_settings;

};

static void i2s_read_done(void *arg);
static void i2s_write_done(void *arg);
static bool chan_filter(struct dma_chan *chan, void *param);
static void i2s_dma_stop(struct intel_mid_i2s_hdl *drv_data);
static int i2s_dma_start(struct intel_mid_i2s_hdl *drv_data);
static void ssp1_dump_registers(struct intel_mid_i2s_hdl *);
static irqreturn_t i2s_int(int irq, void *dev_id);
static void set_ssp_i2s_hw(struct intel_mid_i2s_hdl *drv_data,
		const struct intel_mid_i2s_settings *ps_settings);
static int check_device(struct device *device_ptr, void *data);
#ifdef CONFIG_PM
static int intel_mid_i2s_runtime_resume(struct device *device_ptr);
static int intel_mid_i2s_runtime_suspend(struct device *device_ptr);
#endif
static int intel_mid_i2s_probe(struct pci_dev *pdev,
		const struct pci_device_id *ent);
static void intel_mid_i2s_remove(struct pci_dev *pdev);
static void i2s_ssp_stop(struct intel_mid_i2s_hdl *drv_data);
/*static int bt_pcm_dma_init(struct intel_mid_i2s_hdl *drv_data);*/


#ifdef CONFIG_PM
static int  intel_mid_i2s_driver_suspend(struct pci_dev *dev,
					  pm_message_t state);
static int intel_mid_i2s_driver_resume(struct pci_dev *dev);
#endif

/*
 * These define will clarify source code when accessing SSCRx registers
 */

#define SSCR0_reg(regbit, value)					\
	(((value) & SSCR0_##regbit##_MASK) << SSCR0_##regbit##_SHIFT)

#define SSCR1_reg(regbit, value)					\
	(((value) & SSCR1_##regbit##_MASK) << SSCR1_##regbit##_SHIFT)

#define SSPSP_reg(regbit, value)					\
	(((value) & SSPSP_##regbit##_MASK) << SSPSP_##regbit##_SHIFT)

#define SSRSA_reg(regbit, value)					\
	(((value) & SSRSA_##regbit##_MASK) << SSRSA_##regbit##_SHIFT)
#define SSTSA_reg(regbit, value)					\
	(((value) & SSTSA_##regbit##_MASK) << SSTSA_##regbit##_SHIFT)


#define change_SSCR0_reg(reg_pointer, regbit, value)			  \
	write_SSCR0((read_SSCR0(reg_pointer)				  \
	& (~((SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT))))	  \
	| (((value) & SSCR0_##regbit##_MASK) << SSCR0_##regbit##_SHIFT),  \
	reg_pointer);

#define set_SSCR0_reg(reg_pointer, regbit)				  \
	write_SSCR0(read_SSCR0(reg_pointer)				  \
	| (SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT),		\
	reg_pointer);

#define clear_SSCR0_reg(reg_pointer, regbit)				  \
	write_SSCR0((read_SSCR0(reg_pointer)				  \
	& (~((SSCR0_##regbit##_MASK << SSCR0_##regbit##_SHIFT)))),	  \
	reg_pointer);

#define change_SSCR1_reg(reg_pointer, regbit, value)			  \
	write_SSCR1((read_SSCR1(reg_pointer)				  \
	& (~((SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT))))	  \
	| (((value) & SSCR1_##regbit##_MASK) << SSCR1_##regbit##_SHIFT),  \
	reg_pointer);

#define set_SSCR1_reg(reg_pointer, regbit)				  \
	write_SSCR1(read_SSCR1(reg_pointer)				  \
	| (SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT),		  \
	reg_pointer);

#define clear_SSCR1_reg(reg_pointer, regbit)				  \
	write_SSCR1((read_SSCR1(reg_pointer)				  \
	& (~((SSCR1_##regbit##_MASK << SSCR1_##regbit##_SHIFT)))),	  \
	reg_pointer);

/* RX FIFO level */
#define GET_SSSR_val(x, regb)						  \
	((x & (SSSR_##regb##_MASK<<SSSR_##regb##_SHIFT))>>SSSR_##regb##_SHIFT)


/*
 * SSP hardware can be configured as I2S, PCM, SPI...
 * In order to allow flexibility without modifying the software driver, the
 * PCI header uses the configuration register 'adid':
 *
 * The PCI header associated to SSP devices includes a configuration register.
 * It provides information to a driver which is probed for the SSP, specifying
 * in which way the SSP is supposed to be used.
 * Here is the format of this configuration register (8 bits):
 *
 *   bits 2..0: Mode
 *       000: Invalid, the register should be ignored
 *       001: SSP to be used as SPI controller
 *       010: SSP to be used in I2S/ISS mode
 *       other: Reserved
 *
 *   bits 5..3: Configuration
 *       In I2S/ISS mode:
 *               000: Invalid
 *               001: Bluetooth
 *               010: Modem
 *               other: Reserved
 *       In SPI mode:
 *               Value is the SPI bus number connected to the SSP.
 *               To be used for registration to the Linux SPI
 *               framework.
 *
 *   bit 6: SPI slave
 *       Relevant in SPI mode only. If set, indicates the SPI clock
 *       is not provided by the SSP: SPI slave mode.
 *
 *   bit 7: Reserved (0)
 *
 *   This configuration register is implemented in the adid field of the
 *   Vendor Specific PCI capability associated to the SSP. The format of
 *   this capability is:
 *
 *   uint8_t     capId;              < Capability ID (vendor-specific)
 *   uint8_t     nextCap;            < Next Item Ptr
 *   uint8_t     length;             < Size of this capability (7)
 *   uint8_t     version;            < Version of this capability (1)
 *   uint8_t     lss;                < Logical subsystem info
 *                                         Bit 7 = PMU (0 = NC, 1 = SC)
 *                                         Bits 6:0 = LSS ID
 *   uint8_t     apmc;               < Additional PM capabilities
 *                                         Bit 7 = Rsvd
 *                                         Bit 6 = Wake capable
 *                                         Bit 5 = D3 support
 *                                         Bit 4 = D2 support
 *                                         Bit 3 = D1 support
 *                                         Bit 2 = D0i3 support
 *                                         Bit 1 = D0i2 support
 *                                         Bit 0 = D0i1 support
 *   uint8_t     adid;               < Additional device ID (dev-specific)
 *   uint8_t     rsvd;               < Reserved for future use
 *
 *   The capability data are in the PCI configuration space and the
 *   adid field can be modified using BMP tool.
 */
/* ADDID = Additional Device ID */
#define PCI_CAP_OFFSET_ADID 6