diff options
Diffstat (limited to 'sound')
148 files changed, 6215 insertions, 1506 deletions
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 697c166acf05..8eb58c709b14 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c | |||
@@ -106,8 +106,9 @@ EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); | |||
106 | * direction of the substream. If the substream is a playback stream the dst | 106 | * direction of the substream. If the substream is a playback stream the dst |
107 | * fields will be initialized, if it is a capture stream the src fields will be | 107 | * fields will be initialized, if it is a capture stream the src fields will be |
108 | * initialized. The {dst,src}_addr_width field will only be initialized if the | 108 | * initialized. The {dst,src}_addr_width field will only be initialized if the |
109 | * addr_width field of the DAI DMA data struct is not equal to | 109 | * SND_DMAENGINE_PCM_DAI_FLAG_PACK flag is set or if the addr_width field of |
110 | * DMA_SLAVE_BUSWIDTH_UNDEFINED. | 110 | * the DAI DMA data struct is not equal to DMA_SLAVE_BUSWIDTH_UNDEFINED. If |
111 | * both conditions are met the latter takes priority. | ||
111 | */ | 112 | */ |
112 | void snd_dmaengine_pcm_set_config_from_dai_data( | 113 | void snd_dmaengine_pcm_set_config_from_dai_data( |
113 | const struct snd_pcm_substream *substream, | 114 | const struct snd_pcm_substream *substream, |
@@ -117,11 +118,17 @@ void snd_dmaengine_pcm_set_config_from_dai_data( | |||
117 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 118 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
118 | slave_config->dst_addr = dma_data->addr; | 119 | slave_config->dst_addr = dma_data->addr; |
119 | slave_config->dst_maxburst = dma_data->maxburst; | 120 | slave_config->dst_maxburst = dma_data->maxburst; |
121 | if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK) | ||
122 | slave_config->dst_addr_width = | ||
123 | DMA_SLAVE_BUSWIDTH_UNDEFINED; | ||
120 | if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) | 124 | if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) |
121 | slave_config->dst_addr_width = dma_data->addr_width; | 125 | slave_config->dst_addr_width = dma_data->addr_width; |
122 | } else { | 126 | } else { |
123 | slave_config->src_addr = dma_data->addr; | 127 | slave_config->src_addr = dma_data->addr; |
124 | slave_config->src_maxburst = dma_data->maxburst; | 128 | slave_config->src_maxburst = dma_data->maxburst; |
129 | if (dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK) | ||
130 | slave_config->src_addr_width = | ||
131 | DMA_SLAVE_BUSWIDTH_UNDEFINED; | ||
125 | if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) | 132 | if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) |
126 | slave_config->src_addr_width = dma_data->addr_width; | 133 | slave_config->src_addr_width = dma_data->addr_width; |
127 | } | 134 | } |
diff --git a/sound/core/pcm_iec958.c b/sound/core/pcm_iec958.c index 36b2d7aca1bd..5e6aed64f451 100644 --- a/sound/core/pcm_iec958.c +++ b/sound/core/pcm_iec958.c | |||
@@ -9,30 +9,18 @@ | |||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <sound/asoundef.h> | 10 | #include <sound/asoundef.h> |
11 | #include <sound/pcm.h> | 11 | #include <sound/pcm.h> |
12 | #include <sound/pcm_params.h> | ||
12 | #include <sound/pcm_iec958.h> | 13 | #include <sound/pcm_iec958.h> |
13 | 14 | ||
14 | /** | 15 | static int create_iec958_consumer(uint rate, uint sample_width, |
15 | * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status | 16 | u8 *cs, size_t len) |
16 | * @runtime: pcm runtime structure with ->rate filled in | ||
17 | * @cs: channel status buffer, at least four bytes | ||
18 | * @len: length of channel status buffer | ||
19 | * | ||
20 | * Create the consumer format channel status data in @cs of maximum size | ||
21 | * @len corresponding to the parameters of the PCM runtime @runtime. | ||
22 | * | ||
23 | * Drivers may wish to tweak the contents of the buffer after creation. | ||
24 | * | ||
25 | * Returns: length of buffer, or negative error code if something failed. | ||
26 | */ | ||
27 | int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | ||
28 | size_t len) | ||
29 | { | 17 | { |
30 | unsigned int fs, ws; | 18 | unsigned int fs, ws; |
31 | 19 | ||
32 | if (len < 4) | 20 | if (len < 4) |
33 | return -EINVAL; | 21 | return -EINVAL; |
34 | 22 | ||
35 | switch (runtime->rate) { | 23 | switch (rate) { |
36 | case 32000: | 24 | case 32000: |
37 | fs = IEC958_AES3_CON_FS_32000; | 25 | fs = IEC958_AES3_CON_FS_32000; |
38 | break; | 26 | break; |
@@ -59,7 +47,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | |||
59 | } | 47 | } |
60 | 48 | ||
61 | if (len > 4) { | 49 | if (len > 4) { |
62 | switch (snd_pcm_format_width(runtime->format)) { | 50 | switch (sample_width) { |
63 | case 16: | 51 | case 16: |
64 | ws = IEC958_AES4_CON_WORDLEN_20_16; | 52 | ws = IEC958_AES4_CON_WORDLEN_20_16; |
65 | break; | 53 | break; |
@@ -71,6 +59,7 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | |||
71 | IEC958_AES4_CON_MAX_WORDLEN_24; | 59 | IEC958_AES4_CON_MAX_WORDLEN_24; |
72 | break; | 60 | break; |
73 | case 24: | 61 | case 24: |
62 | case 32: /* Assume 24-bit width for 32-bit samples. */ | ||
74 | ws = IEC958_AES4_CON_WORDLEN_24_20 | | 63 | ws = IEC958_AES4_CON_WORDLEN_24_20 | |
75 | IEC958_AES4_CON_MAX_WORDLEN_24; | 64 | IEC958_AES4_CON_MAX_WORDLEN_24; |
76 | break; | 65 | break; |
@@ -92,4 +81,46 @@ int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | |||
92 | 81 | ||
93 | return len; | 82 | return len; |
94 | } | 83 | } |
84 | |||
85 | /** | ||
86 | * snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status | ||
87 | * @runtime: pcm runtime structure with ->rate filled in | ||
88 | * @cs: channel status buffer, at least four bytes | ||
89 | * @len: length of channel status buffer | ||
90 | * | ||
91 | * Create the consumer format channel status data in @cs of maximum size | ||
92 | * @len corresponding to the parameters of the PCM runtime @runtime. | ||
93 | * | ||
94 | * Drivers may wish to tweak the contents of the buffer after creation. | ||
95 | * | ||
96 | * Returns: length of buffer, or negative error code if something failed. | ||
97 | */ | ||
98 | int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs, | ||
99 | size_t len) | ||
100 | { | ||
101 | return create_iec958_consumer(runtime->rate, | ||
102 | snd_pcm_format_width(runtime->format), | ||
103 | cs, len); | ||
104 | } | ||
95 | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); | 105 | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer); |
106 | |||
107 | /** | ||
108 | * snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status | ||
109 | * @hw_params: the hw_params instance for extracting rate and sample format | ||
110 | * @cs: channel status buffer, at least four bytes | ||
111 | * @len: length of channel status buffer | ||
112 | * | ||
113 | * Create the consumer format channel status data in @cs of maximum size | ||
114 | * @len corresponding to the parameters of the PCM runtime @runtime. | ||
115 | * | ||
116 | * Drivers may wish to tweak the contents of the buffer after creation. | ||
117 | * | ||
118 | * Returns: length of buffer, or negative error code if something failed. | ||
119 | */ | ||
120 | int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params, | ||
121 | u8 *cs, size_t len) | ||
122 | { | ||
123 | return create_iec958_consumer(params_rate(params), params_width(params), | ||
124 | cs, len); | ||
125 | } | ||
126 | EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params); | ||
diff --git a/sound/core/timer.c b/sound/core/timer.c index aa1b15c155d1..6469bedda2f3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -1019,8 +1019,8 @@ static int snd_timer_s_start(struct snd_timer * timer) | |||
1019 | njiff += timer->sticks - priv->correction; | 1019 | njiff += timer->sticks - priv->correction; |
1020 | priv->correction = 0; | 1020 | priv->correction = 0; |
1021 | } | 1021 | } |
1022 | priv->last_expires = priv->tlist.expires = njiff; | 1022 | priv->last_expires = njiff; |
1023 | add_timer(&priv->tlist); | 1023 | mod_timer(&priv->tlist, njiff); |
1024 | return 0; | 1024 | return 0; |
1025 | } | 1025 | } |
1026 | 1026 | ||
@@ -1502,17 +1502,13 @@ static int snd_timer_user_ginfo(struct file *file, | |||
1502 | return err; | 1502 | return err; |
1503 | } | 1503 | } |
1504 | 1504 | ||
1505 | static int snd_timer_user_gparams(struct file *file, | 1505 | static int timer_set_gparams(struct snd_timer_gparams *gparams) |
1506 | struct snd_timer_gparams __user *_gparams) | ||
1507 | { | 1506 | { |
1508 | struct snd_timer_gparams gparams; | ||
1509 | struct snd_timer *t; | 1507 | struct snd_timer *t; |
1510 | int err; | 1508 | int err; |
1511 | 1509 | ||
1512 | if (copy_from_user(&gparams, _gparams, sizeof(gparams))) | ||
1513 | return -EFAULT; | ||
1514 | mutex_lock(®ister_mutex); | 1510 | mutex_lock(®ister_mutex); |
1515 | t = snd_timer_find(&gparams.tid); | 1511 | t = snd_timer_find(&gparams->tid); |
1516 | if (!t) { | 1512 | if (!t) { |
1517 | err = -ENODEV; | 1513 | err = -ENODEV; |
1518 | goto _error; | 1514 | goto _error; |
@@ -1525,12 +1521,22 @@ static int snd_timer_user_gparams(struct file *file, | |||
1525 | err = -ENOSYS; | 1521 | err = -ENOSYS; |
1526 | goto _error; | 1522 | goto _error; |
1527 | } | 1523 | } |
1528 | err = t->hw.set_period(t, gparams.period_num, gparams.period_den); | 1524 | err = t->hw.set_period(t, gparams->period_num, gparams->period_den); |
1529 | _error: | 1525 | _error: |
1530 | mutex_unlock(®ister_mutex); | 1526 | mutex_unlock(®ister_mutex); |
1531 | return err; | 1527 | return err; |
1532 | } | 1528 | } |
1533 | 1529 | ||
1530 | static int snd_timer_user_gparams(struct file *file, | ||
1531 | struct snd_timer_gparams __user *_gparams) | ||
1532 | { | ||
1533 | struct snd_timer_gparams gparams; | ||
1534 | |||
1535 | if (copy_from_user(&gparams, _gparams, sizeof(gparams))) | ||
1536 | return -EFAULT; | ||
1537 | return timer_set_gparams(&gparams); | ||
1538 | } | ||
1539 | |||
1534 | static int snd_timer_user_gstatus(struct file *file, | 1540 | static int snd_timer_user_gstatus(struct file *file, |
1535 | struct snd_timer_gstatus __user *_gstatus) | 1541 | struct snd_timer_gstatus __user *_gstatus) |
1536 | { | 1542 | { |
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c index 2e908225d754..6a437eb66115 100644 --- a/sound/core/timer_compat.c +++ b/sound/core/timer_compat.c | |||
@@ -22,6 +22,19 @@ | |||
22 | 22 | ||
23 | #include <linux/compat.h> | 23 | #include <linux/compat.h> |
24 | 24 | ||
25 | /* | ||
26 | * ILP32/LP64 has different size for 'long' type. Additionally, the size | ||
27 | * of storage alignment differs depending on architectures. Here, '__packed' | ||
28 | * qualifier is used so that the size of this structure is multiple of 4 and | ||
29 | * it fits to any architectures with 32 bit storage alignment. | ||
30 | */ | ||
31 | struct snd_timer_gparams32 { | ||
32 | struct snd_timer_id tid; | ||
33 | u32 period_num; | ||
34 | u32 period_den; | ||
35 | unsigned char reserved[32]; | ||
36 | } __packed; | ||
37 | |||
25 | struct snd_timer_info32 { | 38 | struct snd_timer_info32 { |
26 | u32 flags; | 39 | u32 flags; |
27 | s32 card; | 40 | s32 card; |
@@ -32,6 +45,19 @@ struct snd_timer_info32 { | |||
32 | unsigned char reserved[64]; | 45 | unsigned char reserved[64]; |
33 | }; | 46 | }; |
34 | 47 | ||
48 | static int snd_timer_user_gparams_compat(struct file *file, | ||
49 | struct snd_timer_gparams32 __user *user) | ||
50 | { | ||
51 | struct snd_timer_gparams gparams; | ||
52 | |||
53 | if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) || | ||
54 | get_user(gparams.period_num, &user->period_num) || | ||
55 | get_user(gparams.period_den, &user->period_den)) | ||
56 | return -EFAULT; | ||
57 | |||
58 | return timer_set_gparams(&gparams); | ||
59 | } | ||
60 | |||
35 | static int snd_timer_user_info_compat(struct file *file, | 61 | static int snd_timer_user_info_compat(struct file *file, |
36 | struct snd_timer_info32 __user *_info) | 62 | struct snd_timer_info32 __user *_info) |
37 | { | 63 | { |
@@ -99,6 +125,7 @@ static int snd_timer_user_status_compat(struct file *file, | |||
99 | */ | 125 | */ |
100 | 126 | ||
101 | enum { | 127 | enum { |
128 | SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32), | ||
102 | SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), | 129 | SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), |
103 | SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), | 130 | SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), |
104 | #ifdef CONFIG_X86_X32 | 131 | #ifdef CONFIG_X86_X32 |
@@ -114,7 +141,6 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns | |||
114 | case SNDRV_TIMER_IOCTL_PVERSION: | 141 | case SNDRV_TIMER_IOCTL_PVERSION: |
115 | case SNDRV_TIMER_IOCTL_TREAD: | 142 | case SNDRV_TIMER_IOCTL_TREAD: |
116 | case SNDRV_TIMER_IOCTL_GINFO: | 143 | case SNDRV_TIMER_IOCTL_GINFO: |
117 | case SNDRV_TIMER_IOCTL_GPARAMS: | ||
118 | case SNDRV_TIMER_IOCTL_GSTATUS: | 144 | case SNDRV_TIMER_IOCTL_GSTATUS: |
119 | case SNDRV_TIMER_IOCTL_SELECT: | 145 | case SNDRV_TIMER_IOCTL_SELECT: |
120 | case SNDRV_TIMER_IOCTL_PARAMS: | 146 | case SNDRV_TIMER_IOCTL_PARAMS: |
@@ -128,6 +154,8 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns | |||
128 | case SNDRV_TIMER_IOCTL_PAUSE_OLD: | 154 | case SNDRV_TIMER_IOCTL_PAUSE_OLD: |
129 | case SNDRV_TIMER_IOCTL_NEXT_DEVICE: | 155 | case SNDRV_TIMER_IOCTL_NEXT_DEVICE: |
130 | return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); | 156 | return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); |
157 | case SNDRV_TIMER_IOCTL_GPARAMS32: | ||
158 | return snd_timer_user_gparams_compat(file, argp); | ||
131 | case SNDRV_TIMER_IOCTL_INFO32: | 159 | case SNDRV_TIMER_IOCTL_INFO32: |
132 | return snd_timer_user_info_compat(file, argp); | 160 | return snd_timer_user_info_compat(file, argp); |
133 | case SNDRV_TIMER_IOCTL_STATUS32: | 161 | case SNDRV_TIMER_IOCTL_STATUS32: |
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 845d5e5884a4..ec4db3a514fc 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c | |||
@@ -446,18 +446,12 @@ end: | |||
446 | 446 | ||
447 | void snd_dice_stream_destroy_duplex(struct snd_dice *dice) | 447 | void snd_dice_stream_destroy_duplex(struct snd_dice *dice) |
448 | { | 448 | { |
449 | struct reg_params tx_params, rx_params; | 449 | unsigned int i; |
450 | |||
451 | snd_dice_transaction_clear_enable(dice); | ||
452 | 450 | ||
453 | if (get_register_params(dice, &tx_params, &rx_params) == 0) { | 451 | for (i = 0; i < MAX_STREAMS; i++) { |
454 | stop_streams(dice, AMDTP_IN_STREAM, &tx_params); | 452 | destroy_stream(dice, AMDTP_IN_STREAM, i); |
455 | stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); | 453 | destroy_stream(dice, AMDTP_OUT_STREAM, i); |
456 | } | 454 | } |
457 | |||
458 | release_resources(dice); | ||
459 | |||
460 | dice->substreams_counter = 0; | ||
461 | } | 455 | } |
462 | 456 | ||
463 | void snd_dice_stream_update_duplex(struct snd_dice *dice) | 457 | void snd_dice_stream_update_duplex(struct snd_dice *dice) |
diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 2433f7c81472..3b7ae24900fd 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c | |||
@@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev, | |||
105 | INIT_LIST_HEAD(&ebus->hlink_list); | 105 | INIT_LIST_HEAD(&ebus->hlink_list); |
106 | ebus->idx = idx++; | 106 | ebus->idx = idx++; |
107 | 107 | ||
108 | mutex_init(&ebus->lock); | ||
109 | ebus->cmd_dma_state = true; | ||
110 | |||
108 | return 0; | 111 | return 0; |
109 | } | 112 | } |
110 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); | 113 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); |
diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 548cc1e4114b..860f8cad6602 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c | |||
@@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) | |||
186 | hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); | 186 | hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); |
187 | hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); | 187 | hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); |
188 | 188 | ||
189 | /* since link in On, update the ref */ | ||
190 | hlink->ref_count = 1; | ||
191 | |||
189 | list_add_tail(&hlink->list, &ebus->hlink_list); | 192 | list_add_tail(&hlink->list, &ebus->hlink_list); |
190 | } | 193 | } |
191 | 194 | ||
@@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus) | |||
327 | return 0; | 330 | return 0; |
328 | } | 331 | } |
329 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); | 332 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); |
333 | |||
334 | int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, | ||
335 | struct hdac_ext_link *link) | ||
336 | { | ||
337 | int ret = 0; | ||
338 | |||
339 | mutex_lock(&ebus->lock); | ||
340 | |||
341 | /* | ||
342 | * if we move from 0 to 1, count will be 1 so power up this link | ||
343 | * as well, also check the dma status and trigger that | ||
344 | */ | ||
345 | if (++link->ref_count == 1) { | ||
346 | if (!ebus->cmd_dma_state) { | ||
347 | snd_hdac_bus_init_cmd_io(&ebus->bus); | ||
348 | ebus->cmd_dma_state = true; | ||
349 | } | ||
350 | |||
351 | ret = snd_hdac_ext_bus_link_power_up(link); | ||
352 | } | ||
353 | |||
354 | mutex_unlock(&ebus->lock); | ||
355 | return ret; | ||
356 | } | ||
357 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); | ||
358 | |||
359 | int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, | ||
360 | struct hdac_ext_link *link) | ||
361 | { | ||
362 | int ret = 0; | ||
363 | struct hdac_ext_link *hlink; | ||
364 | bool link_up = false; | ||
365 | |||
366 | mutex_lock(&ebus->lock); | ||
367 | |||
368 | /* | ||
369 | * if we move from 1 to 0, count will be 0 | ||
370 | * so power down this link as well | ||
371 | */ | ||
372 | if (--link->ref_count == 0) { | ||
373 | ret = snd_hdac_ext_bus_link_power_down(link); | ||
374 | |||
375 | /* | ||
376 | * now check if all links are off, if so turn off | ||
377 | * cmd dma as well | ||
378 | */ | ||
379 | list_for_each_entry(hlink, &ebus->hlink_list, list) { | ||
380 | if (hlink->ref_count) { | ||
381 | link_up = true; | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | if (!link_up) { | ||
387 | snd_hdac_bus_stop_cmd_io(&ebus->bus); | ||
388 | ebus->cmd_dma_state = false; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | mutex_unlock(&ebus->lock); | ||
393 | return ret; | ||
394 | } | ||
395 | EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put); | ||
diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index 023cc4cad5c1..626f3bb24c55 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c | |||
@@ -104,12 +104,11 @@ EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_init_all); | |||
104 | */ | 104 | */ |
105 | void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus) | 105 | void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus) |
106 | { | 106 | { |
107 | struct hdac_stream *s; | 107 | struct hdac_stream *s, *_s; |
108 | struct hdac_ext_stream *stream; | 108 | struct hdac_ext_stream *stream; |
109 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 109 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
110 | 110 | ||
111 | while (!list_empty(&bus->stream_list)) { | 111 | list_for_each_entry_safe(s, _s, &bus->stream_list, list) { |
112 | s = list_first_entry(&bus->stream_list, struct hdac_stream, list); | ||
113 | stream = stream_to_hdac_ext_stream(s); | 112 | stream = stream_to_hdac_ext_stream(s); |
114 | snd_hdac_ext_stream_decouple(ebus, stream, false); | 113 | snd_hdac_ext_stream_decouple(ebus, stream, false); |
115 | list_del(&s->list); | 114 | list_del(&s->list); |
diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index d1a4d6973330..03c9872c31cf 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c | |||
@@ -299,13 +299,11 @@ EXPORT_SYMBOL_GPL(_snd_hdac_read_parm); | |||
299 | int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, | 299 | int snd_hdac_read_parm_uncached(struct hdac_device *codec, hda_nid_t nid, |
300 | int parm) | 300 | int parm) |
301 | { | 301 | { |
302 | int val; | 302 | unsigned int cmd, val; |
303 | 303 | ||
304 | if (codec->regmap) | 304 | cmd = snd_hdac_regmap_encode_verb(nid, AC_VERB_PARAMETERS) | parm; |
305 | regcache_cache_bypass(codec->regmap, true); | 305 | if (snd_hdac_regmap_read_raw_uncached(codec, cmd, &val) < 0) |
306 | val = snd_hdac_read_parm(codec, nid, parm); | 306 | return -1; |
307 | if (codec->regmap) | ||
308 | regcache_cache_bypass(codec->regmap, false); | ||
309 | return val; | 307 | return val; |
310 | } | 308 | } |
311 | EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); | 309 | EXPORT_SYMBOL_GPL(snd_hdac_read_parm_uncached); |
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index fb96aead8257..607bbeaebddf 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <sound/core.h> | 20 | #include <sound/core.h> |
21 | #include <sound/hdaudio.h> | 21 | #include <sound/hdaudio.h> |
22 | #include <sound/hda_i915.h> | 22 | #include <sound/hda_i915.h> |
23 | #include <sound/hda_register.h> | ||
23 | 24 | ||
24 | static struct i915_audio_component *hdac_acomp; | 25 | static struct i915_audio_component *hdac_acomp; |
25 | 26 | ||
@@ -97,26 +98,65 @@ int snd_hdac_display_power(struct hdac_bus *bus, bool enable) | |||
97 | } | 98 | } |
98 | EXPORT_SYMBOL_GPL(snd_hdac_display_power); | 99 | EXPORT_SYMBOL_GPL(snd_hdac_display_power); |
99 | 100 | ||
101 | #define CONTROLLER_IN_GPU(pci) (((pci)->device == 0x0a0c) || \ | ||
102 | ((pci)->device == 0x0c0c) || \ | ||
103 | ((pci)->device == 0x0d0c) || \ | ||
104 | ((pci)->device == 0x160c)) | ||
105 | |||
100 | /** | 106 | /** |
101 | * snd_hdac_get_display_clk - Get CDCLK in kHz | 107 | * snd_hdac_i915_set_bclk - Reprogram BCLK for HSW/BDW |
102 | * @bus: HDA core bus | 108 | * @bus: HDA core bus |
103 | * | 109 | * |
104 | * This function is supposed to be used only by a HD-audio controller | 110 | * Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK |
105 | * driver that needs the interaction with i915 graphics. | 111 | * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) |
112 | * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: | ||
113 | * BCLK = CDCLK * M / N | ||
114 | * The values will be lost when the display power well is disabled and need to | ||
115 | * be restored to avoid abnormal playback speed. | ||
106 | * | 116 | * |
107 | * This function queries CDCLK value in kHz from the graphics driver and | 117 | * Call this function at initializing and changing power well, as well as |
108 | * returns the value. A negative code is returned in error. | 118 | * at ELD notifier for the hotplug. |
109 | */ | 119 | */ |
110 | int snd_hdac_get_display_clk(struct hdac_bus *bus) | 120 | void snd_hdac_i915_set_bclk(struct hdac_bus *bus) |
111 | { | 121 | { |
112 | struct i915_audio_component *acomp = bus->audio_component; | 122 | struct i915_audio_component *acomp = bus->audio_component; |
123 | struct pci_dev *pci = to_pci_dev(bus->dev); | ||
124 | int cdclk_freq; | ||
125 | unsigned int bclk_m, bclk_n; | ||
126 | |||
127 | if (!acomp || !acomp->ops || !acomp->ops->get_cdclk_freq) | ||
128 | return; /* only for i915 binding */ | ||
129 | if (!CONTROLLER_IN_GPU(pci)) | ||
130 | return; /* only HSW/BDW */ | ||
131 | |||
132 | cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev); | ||
133 | switch (cdclk_freq) { | ||
134 | case 337500: | ||
135 | bclk_m = 16; | ||
136 | bclk_n = 225; | ||
137 | break; | ||
138 | |||
139 | case 450000: | ||
140 | default: /* default CDCLK 450MHz */ | ||
141 | bclk_m = 4; | ||
142 | bclk_n = 75; | ||
143 | break; | ||
144 | |||
145 | case 540000: | ||
146 | bclk_m = 4; | ||
147 | bclk_n = 90; | ||
148 | break; | ||
149 | |||
150 | case 675000: | ||
151 | bclk_m = 8; | ||
152 | bclk_n = 225; | ||
153 | break; | ||
154 | } | ||
113 | 155 | ||
114 | if (!acomp || !acomp->ops) | 156 | snd_hdac_chip_writew(bus, HSW_EM4, bclk_m); |
115 | return -ENODEV; | 157 | snd_hdac_chip_writew(bus, HSW_EM5, bclk_n); |
116 | |||
117 | return acomp->ops->get_cdclk_freq(acomp->dev); | ||
118 | } | 158 | } |
119 | EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); | 159 | EXPORT_SYMBOL_GPL(snd_hdac_i915_set_bclk); |
120 | 160 | ||
121 | /* There is a fixed mapping between audio pin node and display port | 161 | /* There is a fixed mapping between audio pin node and display port |
122 | * on current Intel platforms: | 162 | * on current Intel platforms: |
@@ -267,6 +307,18 @@ int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops | |||
267 | } | 307 | } |
268 | EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier); | 308 | EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier); |
269 | 309 | ||
310 | /* check whether intel graphics is present */ | ||
311 | static bool i915_gfx_present(void) | ||
312 | { | ||
313 | static struct pci_device_id ids[] = { | ||
314 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID), | ||
315 | .class = PCI_BASE_CLASS_DISPLAY << 16, | ||
316 | .class_mask = 0xff << 16 }, | ||
317 | {} | ||
318 | }; | ||
319 | return pci_dev_present(ids); | ||
320 | } | ||
321 | |||
270 | /** | 322 | /** |
271 | * snd_hdac_i915_init - Initialize i915 audio component | 323 | * snd_hdac_i915_init - Initialize i915 audio component |
272 | * @bus: HDA core bus | 324 | * @bus: HDA core bus |
@@ -286,6 +338,9 @@ int snd_hdac_i915_init(struct hdac_bus *bus) | |||
286 | struct i915_audio_component *acomp; | 338 | struct i915_audio_component *acomp; |
287 | int ret; | 339 | int ret; |
288 | 340 | ||
341 | if (!i915_gfx_present()) | ||
342 | return -ENODEV; | ||
343 | |||
289 | acomp = kzalloc(sizeof(*acomp), GFP_KERNEL); | 344 | acomp = kzalloc(sizeof(*acomp), GFP_KERNEL); |
290 | if (!acomp) | 345 | if (!acomp) |
291 | return -ENOMEM; | 346 | return -ENOMEM; |
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index bdbcd6b75ff6..87041ddd29cb 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c | |||
@@ -453,14 +453,30 @@ int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, | |||
453 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw); | 453 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_write_raw); |
454 | 454 | ||
455 | static int reg_raw_read(struct hdac_device *codec, unsigned int reg, | 455 | static int reg_raw_read(struct hdac_device *codec, unsigned int reg, |
456 | unsigned int *val) | 456 | unsigned int *val, bool uncached) |
457 | { | 457 | { |
458 | if (!codec->regmap) | 458 | if (uncached || !codec->regmap) |
459 | return hda_reg_read(codec, reg, val); | 459 | return hda_reg_read(codec, reg, val); |
460 | else | 460 | else |
461 | return regmap_read(codec->regmap, reg, val); | 461 | return regmap_read(codec->regmap, reg, val); |
462 | } | 462 | } |
463 | 463 | ||
464 | static int __snd_hdac_regmap_read_raw(struct hdac_device *codec, | ||
465 | unsigned int reg, unsigned int *val, | ||
466 | bool uncached) | ||
467 | { | ||
468 | int err; | ||
469 | |||
470 | err = reg_raw_read(codec, reg, val, uncached); | ||
471 | if (err == -EAGAIN) { | ||
472 | err = snd_hdac_power_up_pm(codec); | ||
473 | if (!err) | ||
474 | err = reg_raw_read(codec, reg, val, uncached); | ||
475 | snd_hdac_power_down_pm(codec); | ||
476 | } | ||
477 | return err; | ||
478 | } | ||
479 | |||
464 | /** | 480 | /** |
465 | * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt | 481 | * snd_hdac_regmap_read_raw - read a pseudo register with power mgmt |
466 | * @codec: the codec object | 482 | * @codec: the codec object |
@@ -472,19 +488,19 @@ static int reg_raw_read(struct hdac_device *codec, unsigned int reg, | |||
472 | int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, | 488 | int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, |
473 | unsigned int *val) | 489 | unsigned int *val) |
474 | { | 490 | { |
475 | int err; | 491 | return __snd_hdac_regmap_read_raw(codec, reg, val, false); |
476 | |||
477 | err = reg_raw_read(codec, reg, val); | ||
478 | if (err == -EAGAIN) { | ||
479 | err = snd_hdac_power_up_pm(codec); | ||
480 | if (!err) | ||
481 | err = reg_raw_read(codec, reg, val); | ||
482 | snd_hdac_power_down_pm(codec); | ||
483 | } | ||
484 | return err; | ||
485 | } | 492 | } |
486 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw); | 493 | EXPORT_SYMBOL_GPL(snd_hdac_regmap_read_raw); |
487 | 494 | ||
495 | /* Works like snd_hdac_regmap_read_raw(), but this doesn't read from the | ||
496 | * cache but always via hda verbs. | ||
497 | */ | ||
498 | int snd_hdac_regmap_read_raw_uncached(struct hdac_device *codec, | ||
499 | unsigned int reg, unsigned int *val) | ||
500 | { | ||
501 | return __snd_hdac_regmap_read_raw(codec, reg, val, true); | ||
502 | } | ||
503 | |||
488 | /** | 504 | /** |
489 | * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt | 505 | * snd_hdac_regmap_update_raw - update a pseudo register with power mgmt |
490 | * @codec: the codec object | 506 | * @codec: the codec object |
diff --git a/sound/hda/local.h b/sound/hda/local.h index d692f417ddc0..0d5bb159d538 100644 --- a/sound/hda/local.h +++ b/sound/hda/local.h | |||
@@ -16,6 +16,16 @@ static inline int get_wcaps_type(unsigned int wcaps) | |||
16 | return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | 16 | return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; |
17 | } | 17 | } |
18 | 18 | ||
19 | static inline unsigned int get_wcaps_channels(u32 wcaps) | ||
20 | { | ||
21 | unsigned int chans; | ||
22 | |||
23 | chans = (wcaps & AC_WCAP_CHAN_CNT_EXT) >> 13; | ||
24 | chans = (chans + 1) * 2; | ||
25 | |||
26 | return chans; | ||
27 | } | ||
28 | |||
19 | extern const struct attribute_group *hdac_dev_attr_groups[]; | 29 | extern const struct attribute_group *hdac_dev_attr_groups[]; |
20 | int hda_widget_sysfs_init(struct hdac_device *codec); | 30 | int hda_widget_sysfs_init(struct hdac_device *codec); |
21 | void hda_widget_sysfs_exit(struct hdac_device *codec); | 31 | void hda_widget_sysfs_exit(struct hdac_device *codec); |
diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 7b248cdf06e2..fdcfa29e2205 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c | |||
@@ -591,7 +591,7 @@ static int sscape_upload_microcode(struct snd_card *card, int version) | |||
591 | } | 591 | } |
592 | err = upload_dma_data(sscape, init_fw->data, init_fw->size); | 592 | err = upload_dma_data(sscape, init_fw->data, init_fw->size); |
593 | if (err == 0) | 593 | if (err == 0) |
594 | snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n", | 594 | snd_printk(KERN_INFO "sscape: MIDI firmware loaded %zu KBs\n", |
595 | init_fw->size >> 10); | 595 | init_fw->size >> 10); |
596 | 596 | ||
597 | release_firmware(init_fw); | 597 | release_firmware(init_fw); |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 7ca5b89f088a..dfaf1a93fb8a 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -826,7 +826,7 @@ static hda_nid_t path_power_update(struct hda_codec *codec, | |||
826 | bool allow_powerdown) | 826 | bool allow_powerdown) |
827 | { | 827 | { |
828 | hda_nid_t nid, changed = 0; | 828 | hda_nid_t nid, changed = 0; |
829 | int i, state; | 829 | int i, state, power; |
830 | 830 | ||
831 | for (i = 0; i < path->depth; i++) { | 831 | for (i = 0; i < path->depth; i++) { |
832 | nid = path->path[i]; | 832 | nid = path->path[i]; |
@@ -838,7 +838,9 @@ static hda_nid_t path_power_update(struct hda_codec *codec, | |||
838 | state = AC_PWRST_D0; | 838 | state = AC_PWRST_D0; |
839 | else | 839 | else |
840 | state = AC_PWRST_D3; | 840 | state = AC_PWRST_D3; |
841 | if (!snd_hda_check_power_state(codec, nid, state)) { | 841 | power = snd_hda_codec_read(codec, nid, 0, |
842 | AC_VERB_GET_POWER_STATE, 0); | ||
843 | if (power != (state | (state << 4))) { | ||
842 | snd_hda_codec_write(codec, nid, 0, | 844 | snd_hda_codec_write(codec, nid, 0, |
843 | AC_VERB_SET_POWER_STATE, state); | 845 | AC_VERB_SET_POWER_STATE, state); |
844 | changed = nid; | 846 | changed = nid; |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 2624cfe98884..9a0d1445ca5c 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -857,50 +857,6 @@ static int param_set_xint(const char *val, const struct kernel_param *kp) | |||
857 | #define azx_del_card_list(chip) /* NOP */ | 857 | #define azx_del_card_list(chip) /* NOP */ |
858 | #endif /* CONFIG_PM */ | 858 | #endif /* CONFIG_PM */ |
859 | 859 | ||
860 | /* Intel HSW/BDW display HDA controller is in GPU. Both its power and link BCLK | ||
861 | * depends on GPU. Two Extended Mode registers EM4 (M value) and EM5 (N Value) | ||
862 | * are used to convert CDClk (Core Display Clock) to 24MHz BCLK: | ||
863 | * BCLK = CDCLK * M / N | ||
864 | * The values will be lost when the display power well is disabled and need to | ||
865 | * be restored to avoid abnormal playback speed. | ||
866 | */ | ||
867 | static void haswell_set_bclk(struct hda_intel *hda) | ||
868 | { | ||
869 | struct azx *chip = &hda->chip; | ||
870 | int cdclk_freq; | ||
871 | unsigned int bclk_m, bclk_n; | ||
872 | |||
873 | if (!hda->need_i915_power) | ||
874 | return; | ||
875 | |||
876 | cdclk_freq = snd_hdac_get_display_clk(azx_bus(chip)); | ||
877 | switch (cdclk_freq) { | ||
878 | case 337500: | ||
879 | bclk_m = 16; | ||
880 | bclk_n = 225; | ||
881 | break; | ||
882 | |||
883 | case 450000: | ||
884 | default: /* default CDCLK 450MHz */ | ||
885 | bclk_m = 4; | ||
886 | bclk_n = 75; | ||
887 | break; | ||
888 | |||
889 | case 540000: | ||
890 | bclk_m = 4; | ||
891 | bclk_n = 90; | ||
892 | break; | ||
893 | |||
894 | case 675000: | ||
895 | bclk_m = 8; | ||
896 | bclk_n = 225; | ||
897 | break; | ||
898 | } | ||
899 | |||
900 | azx_writew(chip, HSW_EM4, bclk_m); | ||
901 | azx_writew(chip, HSW_EM5, bclk_n); | ||
902 | } | ||
903 | |||
904 | #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) | 860 | #if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO) |
905 | /* | 861 | /* |
906 | * power management | 862 | * power management |
@@ -958,7 +914,7 @@ static int azx_resume(struct device *dev) | |||
958 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL | 914 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL |
959 | && hda->need_i915_power) { | 915 | && hda->need_i915_power) { |
960 | snd_hdac_display_power(azx_bus(chip), true); | 916 | snd_hdac_display_power(azx_bus(chip), true); |
961 | haswell_set_bclk(hda); | 917 | snd_hdac_i915_set_bclk(azx_bus(chip)); |
962 | } | 918 | } |
963 | if (chip->msi) | 919 | if (chip->msi) |
964 | if (pci_enable_msi(pci) < 0) | 920 | if (pci_enable_msi(pci) < 0) |
@@ -1058,7 +1014,7 @@ static int azx_runtime_resume(struct device *dev) | |||
1058 | bus = azx_bus(chip); | 1014 | bus = azx_bus(chip); |
1059 | if (hda->need_i915_power) { | 1015 | if (hda->need_i915_power) { |
1060 | snd_hdac_display_power(bus, true); | 1016 | snd_hdac_display_power(bus, true); |
1061 | haswell_set_bclk(hda); | 1017 | snd_hdac_i915_set_bclk(bus); |
1062 | } else { | 1018 | } else { |
1063 | /* toggle codec wakeup bit for STATESTS read */ | 1019 | /* toggle codec wakeup bit for STATESTS read */ |
1064 | snd_hdac_set_codec_wakeup(bus, true); | 1020 | snd_hdac_set_codec_wakeup(bus, true); |
@@ -1796,12 +1752,8 @@ static int azx_first_init(struct azx *chip) | |||
1796 | /* initialize chip */ | 1752 | /* initialize chip */ |
1797 | azx_init_pci(chip); | 1753 | azx_init_pci(chip); |
1798 | 1754 | ||
1799 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { | 1755 | if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) |
1800 | struct hda_intel *hda; | 1756 | snd_hdac_i915_set_bclk(bus); |
1801 | |||
1802 | hda = container_of(chip, struct hda_intel, chip); | ||
1803 | haswell_set_bclk(hda); | ||
1804 | } | ||
1805 | 1757 | ||
1806 | hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); | 1758 | hda_intel_init_chip(chip, (probe_only[dev] & 2) == 0); |
1807 | 1759 | ||
@@ -2232,6 +2184,9 @@ static const struct pci_device_id azx_ids[] = { | |||
2232 | /* Broxton-P(Apollolake) */ | 2184 | /* Broxton-P(Apollolake) */ |
2233 | { PCI_DEVICE(0x8086, 0x5a98), | 2185 | { PCI_DEVICE(0x8086, 0x5a98), |
2234 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, | 2186 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, |
2187 | /* Broxton-T */ | ||
2188 | { PCI_DEVICE(0x8086, 0x1a98), | ||
2189 | .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON }, | ||
2235 | /* Haswell */ | 2190 | /* Haswell */ |
2236 | { PCI_DEVICE(0x8086, 0x0a0c), | 2191 | { PCI_DEVICE(0x8086, 0x0a0c), |
2237 | .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, | 2192 | .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, |
@@ -2361,6 +2316,10 @@ static const struct pci_device_id azx_ids[] = { | |||
2361 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | 2316 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, |
2362 | { PCI_DEVICE(0x1002, 0xaae8), | 2317 | { PCI_DEVICE(0x1002, 0xaae8), |
2363 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | 2318 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, |
2319 | { PCI_DEVICE(0x1002, 0xaae0), | ||
2320 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | ||
2321 | { PCI_DEVICE(0x1002, 0xaaf0), | ||
2322 | .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, | ||
2364 | /* VIA VT8251/VT8237A */ | 2323 | /* VIA VT8251/VT8237A */ |
2365 | { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, | 2324 | { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, |
2366 | /* VIA GFX VT7122/VX900 */ | 2325 | /* VIA GFX VT7122/VX900 */ |
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 64e0d1d81ca5..9739fce9e032 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c | |||
@@ -141,14 +141,6 @@ static int reconfig_codec(struct hda_codec *codec) | |||
141 | err = snd_hda_codec_configure(codec); | 141 | err = snd_hda_codec_configure(codec); |
142 | if (err < 0) | 142 | if (err < 0) |
143 | goto error; | 143 | goto error; |
144 | /* rebuild PCMs */ | ||
145 | err = snd_hda_codec_build_pcms(codec); | ||
146 | if (err < 0) | ||
147 | goto error; | ||
148 | /* rebuild mixers */ | ||
149 | err = snd_hda_codec_build_controls(codec); | ||
150 | if (err < 0) | ||
151 | goto error; | ||
152 | err = snd_card_register(codec->card); | 144 | err = snd_card_register(codec->card); |
153 | error: | 145 | error: |
154 | snd_hda_power_down(codec); | 146 | snd_hda_power_down(codec); |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index a47e8ae0eb30..80bbadc83721 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -361,6 +361,7 @@ static int cs_parse_auto_config(struct hda_codec *codec) | |||
361 | { | 361 | { |
362 | struct cs_spec *spec = codec->spec; | 362 | struct cs_spec *spec = codec->spec; |
363 | int err; | 363 | int err; |
364 | int i; | ||
364 | 365 | ||
365 | err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); | 366 | err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); |
366 | if (err < 0) | 367 | if (err < 0) |
@@ -370,6 +371,19 @@ static int cs_parse_auto_config(struct hda_codec *codec) | |||
370 | if (err < 0) | 371 | if (err < 0) |
371 | return err; | 372 | return err; |
372 | 373 | ||
374 | /* keep the ADCs powered up when it's dynamically switchable */ | ||
375 | if (spec->gen.dyn_adc_switch) { | ||
376 | unsigned int done = 0; | ||
377 | for (i = 0; i < spec->gen.input_mux.num_items; i++) { | ||
378 | int idx = spec->gen.dyn_adc_idx[i]; | ||
379 | if (done & (1 << idx)) | ||
380 | continue; | ||
381 | snd_hda_gen_fix_pin_power(codec, | ||
382 | spec->gen.adc_nids[idx]); | ||
383 | done |= 1 << idx; | ||
384 | } | ||
385 | } | ||
386 | |||
373 | return 0; | 387 | return 0; |
374 | } | 388 | } |
375 | 389 | ||
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 5af372d01834..a010d704e0e2 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -1396,7 +1396,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, | |||
1396 | struct hda_codec *codec = per_pin->codec; | 1396 | struct hda_codec *codec = per_pin->codec; |
1397 | struct hdmi_spec *spec = codec->spec; | 1397 | struct hdmi_spec *spec = codec->spec; |
1398 | struct hdmi_eld *eld = &spec->temp_eld; | 1398 | struct hdmi_eld *eld = &spec->temp_eld; |
1399 | struct hdmi_eld *pin_eld = &per_pin->sink_eld; | ||
1400 | hda_nid_t pin_nid = per_pin->pin_nid; | 1399 | hda_nid_t pin_nid = per_pin->pin_nid; |
1401 | /* | 1400 | /* |
1402 | * Always execute a GetPinSense verb here, even when called from | 1401 | * Always execute a GetPinSense verb here, even when called from |
@@ -1413,15 +1412,15 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, | |||
1413 | present = snd_hda_pin_sense(codec, pin_nid); | 1412 | present = snd_hda_pin_sense(codec, pin_nid); |
1414 | 1413 | ||
1415 | mutex_lock(&per_pin->lock); | 1414 | mutex_lock(&per_pin->lock); |
1416 | pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); | 1415 | eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); |
1417 | if (pin_eld->monitor_present) | 1416 | if (eld->monitor_present) |
1418 | eld->eld_valid = !!(present & AC_PINSENSE_ELDV); | 1417 | eld->eld_valid = !!(present & AC_PINSENSE_ELDV); |
1419 | else | 1418 | else |
1420 | eld->eld_valid = false; | 1419 | eld->eld_valid = false; |
1421 | 1420 | ||
1422 | codec_dbg(codec, | 1421 | codec_dbg(codec, |
1423 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", | 1422 | "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", |
1424 | codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid); | 1423 | codec->addr, pin_nid, eld->monitor_present, eld->eld_valid); |
1425 | 1424 | ||
1426 | if (eld->eld_valid) { | 1425 | if (eld->eld_valid) { |
1427 | if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer, | 1426 | if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer, |
@@ -1441,7 +1440,7 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, | |||
1441 | else | 1440 | else |
1442 | update_eld(codec, per_pin, eld); | 1441 | update_eld(codec, per_pin, eld); |
1443 | 1442 | ||
1444 | ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid; | 1443 | ret = !repoll || !eld->monitor_present || eld->eld_valid; |
1445 | 1444 | ||
1446 | jack = snd_hda_jack_tbl_get(codec, pin_nid); | 1445 | jack = snd_hda_jack_tbl_get(codec, pin_nid); |
1447 | if (jack) | 1446 | if (jack) |
@@ -1859,6 +1858,8 @@ static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, | |||
1859 | struct hdmi_spec *spec = codec->spec; | 1858 | struct hdmi_spec *spec = codec->spec; |
1860 | struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); | 1859 | struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx); |
1861 | 1860 | ||
1861 | if (!per_pin) | ||
1862 | return; | ||
1862 | mutex_lock(&per_pin->lock); | 1863 | mutex_lock(&per_pin->lock); |
1863 | per_pin->chmap_set = true; | 1864 | per_pin->chmap_set = true; |
1864 | memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap)); | 1865 | memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap)); |
@@ -2231,6 +2232,7 @@ static void intel_pin_eld_notify(void *audio_ptr, int port) | |||
2231 | if (atomic_read(&(codec)->core.in_pm)) | 2232 | if (atomic_read(&(codec)->core.in_pm)) |
2232 | return; | 2233 | return; |
2233 | 2234 | ||
2235 | snd_hdac_i915_set_bclk(&codec->bus->core); | ||
2234 | check_presence_and_report(codec, pin_nid); | 2236 | check_presence_and_report(codec, pin_nid); |
2235 | } | 2237 | } |
2236 | 2238 | ||
@@ -3399,6 +3401,9 @@ static int patch_atihdmi(struct hda_codec *codec) | |||
3399 | spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; | 3401 | spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; |
3400 | spec->ops.setup_stream = atihdmi_setup_stream; | 3402 | spec->ops.setup_stream = atihdmi_setup_stream; |
3401 | 3403 | ||
3404 | spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel; | ||
3405 | spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel; | ||
3406 | |||
3402 | if (!has_amd_full_remap_support(codec)) { | 3407 | if (!has_amd_full_remap_support(codec)) { |
3403 | /* override to ATI/AMD-specific versions with pairwise mapping */ | 3408 | /* override to ATI/AMD-specific versions with pairwise mapping */ |
3404 | spec->chmap.ops.chmap_cea_alloc_validate_get_type = | 3409 | spec->chmap.ops.chmap_cea_alloc_validate_get_type = |
@@ -3406,10 +3411,6 @@ static int patch_atihdmi(struct hda_codec *codec) | |||
3406 | spec->chmap.ops.cea_alloc_to_tlv_chmap = | 3411 | spec->chmap.ops.cea_alloc_to_tlv_chmap = |
3407 | atihdmi_paired_cea_alloc_to_tlv_chmap; | 3412 | atihdmi_paired_cea_alloc_to_tlv_chmap; |
3408 | spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; | 3413 | spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate; |
3409 | spec->chmap.ops.pin_get_slot_channel = | ||
3410 | atihdmi_pin_get_slot_channel; | ||
3411 | spec->chmap.ops.pin_set_slot_channel = | ||
3412 | atihdmi_pin_set_slot_channel; | ||
3413 | } | 3414 | } |
3414 | 3415 | ||
3415 | /* ATI/AMD converters do not advertise all of their capabilities */ | 3416 | /* ATI/AMD converters do not advertise all of their capabilities */ |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4f5ca0b9ce27..4918ffa5ba68 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -4759,6 +4759,8 @@ enum { | |||
4759 | ALC255_FIXUP_DELL_SPK_NOISE, | 4759 | ALC255_FIXUP_DELL_SPK_NOISE, |
4760 | ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, | 4760 | ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, |
4761 | ALC280_FIXUP_HP_HEADSET_MIC, | 4761 | ALC280_FIXUP_HP_HEADSET_MIC, |
4762 | ALC221_FIXUP_HP_FRONT_MIC, | ||
4763 | ALC292_FIXUP_TPT460, | ||
4762 | }; | 4764 | }; |
4763 | 4765 | ||
4764 | static const struct hda_fixup alc269_fixups[] = { | 4766 | static const struct hda_fixup alc269_fixups[] = { |
@@ -5401,6 +5403,19 @@ static const struct hda_fixup alc269_fixups[] = { | |||
5401 | .chained = true, | 5403 | .chained = true, |
5402 | .chain_id = ALC269_FIXUP_HEADSET_MIC, | 5404 | .chain_id = ALC269_FIXUP_HEADSET_MIC, |
5403 | }, | 5405 | }, |
5406 | [ALC221_FIXUP_HP_FRONT_MIC] = { | ||
5407 | .type = HDA_FIXUP_PINS, | ||
5408 | .v.pins = (const struct hda_pintbl[]) { | ||
5409 | { 0x19, 0x02a19020 }, /* Front Mic */ | ||
5410 | { } | ||
5411 | }, | ||
5412 | }, | ||
5413 | [ALC292_FIXUP_TPT460] = { | ||
5414 | .type = HDA_FIXUP_FUNC, | ||
5415 | .v.func = alc_fixup_tpt440_dock, | ||
5416 | .chained = true, | ||
5417 | .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE, | ||
5418 | }, | ||
5404 | }; | 5419 | }; |
5405 | 5420 | ||
5406 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 5421 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
@@ -5434,6 +5449,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5434 | SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 5449 | SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
5435 | SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 5450 | SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
5436 | SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13), | 5451 | SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13), |
5452 | SND_PCI_QUIRK(0x1028, 0x0669, "Dell Optiplex 9020m", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
5437 | SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK), | 5453 | SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK), |
5438 | SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | 5454 | SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), |
5439 | SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 5455 | SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
@@ -5506,6 +5522,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5506 | SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 5522 | SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
5507 | SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 5523 | SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
5508 | SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), | 5524 | SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), |
5525 | SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), | ||
5509 | SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), | 5526 | SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), |
5510 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5527 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
5511 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5528 | SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
@@ -5554,7 +5571,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5554 | SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK), | 5571 | SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK), |
5555 | SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), | 5572 | SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK), |
5556 | SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), | 5573 | SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), |
5557 | SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), | 5574 | SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460), |
5558 | SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), | 5575 | SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), |
5559 | SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), | 5576 | SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), |
5560 | SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), | 5577 | SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), |
@@ -5567,6 +5584,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5567 | SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), | 5584 | SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK), |
5568 | SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), | 5585 | SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK), |
5569 | SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), | 5586 | SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK), |
5587 | SND_PCI_QUIRK(0x17aa, 0x504a, "ThinkPad X260", ALC292_FIXUP_TPT440_DOCK), | ||
5570 | SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), | 5588 | SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), |
5571 | SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 5589 | SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
5572 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), | 5590 | SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), |
@@ -5649,6 +5667,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = { | |||
5649 | {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, | 5667 | {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, |
5650 | {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, | 5668 | {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, |
5651 | {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, | 5669 | {.id = ALC292_FIXUP_TPT440, .name = "tpt440"}, |
5670 | {.id = ALC292_FIXUP_TPT460, .name = "tpt460"}, | ||
5652 | {} | 5671 | {} |
5653 | }; | 5672 | }; |
5654 | #define ALC225_STANDARD_PINS \ | 5673 | #define ALC225_STANDARD_PINS \ |
@@ -6406,6 +6425,8 @@ enum { | |||
6406 | ALC668_FIXUP_AUTO_MUTE, | 6425 | ALC668_FIXUP_AUTO_MUTE, |
6407 | ALC668_FIXUP_DELL_DISABLE_AAMIX, | 6426 | ALC668_FIXUP_DELL_DISABLE_AAMIX, |
6408 | ALC668_FIXUP_DELL_XPS13, | 6427 | ALC668_FIXUP_DELL_XPS13, |
6428 | ALC662_FIXUP_ASUS_Nx50, | ||
6429 | ALC668_FIXUP_ASUS_Nx51, | ||
6409 | }; | 6430 | }; |
6410 | 6431 | ||
6411 | static const struct hda_fixup alc662_fixups[] = { | 6432 | static const struct hda_fixup alc662_fixups[] = { |
@@ -6646,6 +6667,21 @@ static const struct hda_fixup alc662_fixups[] = { | |||
6646 | .type = HDA_FIXUP_FUNC, | 6667 | .type = HDA_FIXUP_FUNC, |
6647 | .v.func = alc_fixup_bass_chmap, | 6668 | .v.func = alc_fixup_bass_chmap, |
6648 | }, | 6669 | }, |
6670 | [ALC662_FIXUP_ASUS_Nx50] = { | ||
6671 | .type = HDA_FIXUP_FUNC, | ||
6672 | .v.func = alc_fixup_auto_mute_via_amp, | ||
6673 | .chained = true, | ||
6674 | .chain_id = ALC662_FIXUP_BASS_1A | ||
6675 | }, | ||
6676 | [ALC668_FIXUP_ASUS_Nx51] = { | ||
6677 | .type = HDA_FIXUP_PINS, | ||
6678 | .v.pins = (const struct hda_pintbl[]) { | ||
6679 | {0x1a, 0x90170151}, /* bass speaker */ | ||
6680 | {} | ||
6681 | }, | ||
6682 | .chained = true, | ||
6683 | .chain_id = ALC662_FIXUP_BASS_CHMAP, | ||
6684 | }, | ||
6649 | }; | 6685 | }; |
6650 | 6686 | ||
6651 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { | 6687 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { |
@@ -6668,10 +6704,14 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { | |||
6668 | SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 6704 | SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
6669 | SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 6705 | SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
6670 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), | 6706 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), |
6671 | SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), | 6707 | SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE), |
6708 | SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50), | ||
6672 | SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), | 6709 | SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A), |
6710 | SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50), | ||
6673 | SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), | 6711 | SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), |
6674 | SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), | 6712 | SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), |
6713 | SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51), | ||
6714 | SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51), | ||
6675 | SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), | 6715 | SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), |
6676 | SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), | 6716 | SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), |
6677 | SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), | 6717 | SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), |
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index c5194f5b150a..d7e71f309299 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c | |||
@@ -1341,5 +1341,6 @@ irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id) | |||
1341 | } | 1341 | } |
1342 | 1342 | ||
1343 | pcxhr_msg_thread(mgr); | 1343 | pcxhr_msg_thread(mgr); |
1344 | mutex_unlock(&mgr->lock); | ||
1344 | return IRQ_HANDLED; | 1345 | return IRQ_HANDLED; |
1345 | } | 1346 | } |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 276897033639..1267e1af0fae 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -652,7 +652,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
652 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) | 652 | rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) |
653 | | SSC_BF(RCMR_STTDLY, 1) | 653 | | SSC_BF(RCMR_STTDLY, 1) |
654 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 654 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
655 | | SSC_BF(RCMR_CKI, SSC_CKI_FALLING) | 655 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
656 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 656 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
657 | | SSC_BF(RCMR_CKS, SSC_CKS_DIV); | 657 | | SSC_BF(RCMR_CKS, SSC_CKS_DIV); |
658 | 658 | ||
@@ -692,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
692 | rcmr = SSC_BF(RCMR_PERIOD, 0) | 692 | rcmr = SSC_BF(RCMR_PERIOD, 0) |
693 | | SSC_BF(RCMR_STTDLY, START_DELAY) | 693 | | SSC_BF(RCMR_STTDLY, START_DELAY) |
694 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 694 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
695 | | SSC_BF(RCMR_CKI, SSC_CKI_FALLING) | 695 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
696 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 696 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
697 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? | 697 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
698 | SSC_CKS_PIN : SSC_CKS_CLOCK); | 698 | SSC_CKS_PIN : SSC_CKS_CLOCK); |
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 5741c0aa6c03..b5d1caa04d8e 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -206,8 +206,8 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream, | |||
206 | stype = substream->stream; | 206 | stype = substream->stream; |
207 | pcd = to_dmadata(substream); | 207 | pcd = to_dmadata(substream); |
208 | 208 | ||
209 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d " | 209 | DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %zu " |
210 | "runtime->min_align %d\n", | 210 | "runtime->min_align %lu\n", |
211 | (unsigned long)runtime->dma_area, | 211 | (unsigned long)runtime->dma_area, |
212 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, | 212 | (unsigned long)runtime->dma_addr, runtime->dma_bytes, |
213 | runtime->min_align); | 213 | runtime->min_align); |
diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 1c1f2210387b..6ba20498202e 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c | |||
@@ -259,6 +259,9 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, | |||
259 | case SNDRV_PCM_FORMAT_S16_LE: | 259 | case SNDRV_PCM_FORMAT_S16_LE: |
260 | data_length = 16; | 260 | data_length = 16; |
261 | break; | 261 | break; |
262 | case SNDRV_PCM_FORMAT_S24_LE: | ||
263 | data_length = 24; | ||
264 | break; | ||
262 | case SNDRV_PCM_FORMAT_S32_LE: | 265 | case SNDRV_PCM_FORMAT_S32_LE: |
263 | data_length = 32; | 266 | data_length = 32; |
264 | break; | 267 | break; |
@@ -273,13 +276,20 @@ static int bcm2835_i2s_hw_params(struct snd_pcm_substream *substream, | |||
273 | /* otherwise calculate a fitting block ratio */ | 276 | /* otherwise calculate a fitting block ratio */ |
274 | bclk_ratio = 2 * data_length; | 277 | bclk_ratio = 2 * data_length; |
275 | 278 | ||
276 | /* set target clock rate*/ | 279 | /* Clock should only be set up here if CPU is clock master */ |
277 | clk_set_rate(dev->clk, sampling_rate * bclk_ratio); | 280 | switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
281 | case SND_SOC_DAIFMT_CBS_CFS: | ||
282 | case SND_SOC_DAIFMT_CBS_CFM: | ||
283 | clk_set_rate(dev->clk, sampling_rate * bclk_ratio); | ||
284 | break; | ||
285 | default: | ||
286 | break; | ||
287 | } | ||
278 | 288 | ||
279 | /* Setup the frame format */ | 289 | /* Setup the frame format */ |
280 | format = BCM2835_I2S_CHEN; | 290 | format = BCM2835_I2S_CHEN; |
281 | 291 | ||
282 | if (data_length > 24) | 292 | if (data_length >= 24) |
283 | format |= BCM2835_I2S_CHWEX; | 293 | format |= BCM2835_I2S_CHWEX; |
284 | 294 | ||
285 | format |= BCM2835_I2S_CHWID((data_length-8)&0xf); | 295 | format |= BCM2835_I2S_CHWID((data_length-8)&0xf); |
@@ -570,6 +580,7 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = { | |||
570 | .channels_max = 2, | 580 | .channels_max = 2, |
571 | .rates = SNDRV_PCM_RATE_8000_192000, | 581 | .rates = SNDRV_PCM_RATE_8000_192000, |
572 | .formats = SNDRV_PCM_FMTBIT_S16_LE | 582 | .formats = SNDRV_PCM_FMTBIT_S16_LE |
583 | | SNDRV_PCM_FMTBIT_S24_LE | ||
573 | | SNDRV_PCM_FMTBIT_S32_LE | 584 | | SNDRV_PCM_FMTBIT_S32_LE |
574 | }, | 585 | }, |
575 | .capture = { | 586 | .capture = { |
@@ -577,6 +588,7 @@ static struct snd_soc_dai_driver bcm2835_i2s_dai = { | |||
577 | .channels_max = 2, | 588 | .channels_max = 2, |
578 | .rates = SNDRV_PCM_RATE_8000_192000, | 589 | .rates = SNDRV_PCM_RATE_8000_192000, |
579 | .formats = SNDRV_PCM_FMTBIT_S16_LE | 590 | .formats = SNDRV_PCM_FMTBIT_S16_LE |
591 | | SNDRV_PCM_FMTBIT_S24_LE | ||
580 | | SNDRV_PCM_FMTBIT_S32_LE | 592 | | SNDRV_PCM_FMTBIT_S32_LE |
581 | }, | 593 | }, |
582 | .ops = &bcm2835_i2s_dai_ops, | 594 | .ops = &bcm2835_i2s_dai_ops, |
@@ -678,6 +690,15 @@ static int bcm2835_i2s_probe(struct platform_device *pdev) | |||
678 | dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; | 690 | dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; |
679 | dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; | 691 | dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; |
680 | 692 | ||
693 | /* | ||
694 | * Set the PACK flag to enable S16_LE support (2 S16_LE values | ||
695 | * packed into 32-bit transfers). | ||
696 | */ | ||
697 | dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].flags = | ||
698 | SND_DMAENGINE_PCM_DAI_FLAG_PACK; | ||
699 | dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].flags = | ||
700 | SND_DMAENGINE_PCM_DAI_FLAG_PACK; | ||
701 | |||
681 | /* BCLK ratio - use default */ | 702 | /* BCLK ratio - use default */ |
682 | dev->bclk_ratio = 0; | 703 | dev->bclk_ratio = 0; |
683 | 704 | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 649e92a252ae..4d82a58ff6b0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS | |||
43 | select SND_SOC_AK5386 | 43 | select SND_SOC_AK5386 |
44 | select SND_SOC_ALC5623 if I2C | 44 | select SND_SOC_ALC5623 if I2C |
45 | select SND_SOC_ALC5632 if I2C | 45 | select SND_SOC_ALC5632 if I2C |
46 | select SND_SOC_BT_SCO | ||
46 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 47 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
47 | select SND_SOC_CS35L32 if I2C | 48 | select SND_SOC_CS35L32 if I2C |
48 | select SND_SOC_CS42L51_I2C if I2C | 49 | select SND_SOC_CS42L51_I2C if I2C |
@@ -64,7 +65,6 @@ config SND_SOC_ALL_CODECS | |||
64 | select SND_SOC_DA732X if I2C | 65 | select SND_SOC_DA732X if I2C |
65 | select SND_SOC_DA9055 if I2C | 66 | select SND_SOC_DA9055 if I2C |
66 | select SND_SOC_DMIC | 67 | select SND_SOC_DMIC |
67 | select SND_SOC_BT_SCO | ||
68 | select SND_SOC_ES8328_SPI if SPI_MASTER | 68 | select SND_SOC_ES8328_SPI if SPI_MASTER |
69 | select SND_SOC_ES8328_I2C if I2C | 69 | select SND_SOC_ES8328_I2C if I2C |
70 | select SND_SOC_GTM601 | 70 | select SND_SOC_GTM601 |
@@ -79,6 +79,7 @@ config SND_SOC_ALL_CODECS | |||
79 | select SND_SOC_MAX98090 if I2C | 79 | select SND_SOC_MAX98090 if I2C |
80 | select SND_SOC_MAX98095 if I2C | 80 | select SND_SOC_MAX98095 if I2C |
81 | select SND_SOC_MAX98357A if GPIOLIB | 81 | select SND_SOC_MAX98357A if GPIOLIB |
82 | select SND_SOC_MAX98371 if I2C | ||
82 | select SND_SOC_MAX9867 if I2C | 83 | select SND_SOC_MAX9867 if I2C |
83 | select SND_SOC_MAX98925 if I2C | 84 | select SND_SOC_MAX98925 if I2C |
84 | select SND_SOC_MAX98926 if I2C | 85 | select SND_SOC_MAX98926 if I2C |
@@ -88,12 +89,14 @@ config SND_SOC_ALL_CODECS | |||
88 | select SND_SOC_MC13783 if MFD_MC13XXX | 89 | select SND_SOC_MC13783 if MFD_MC13XXX |
89 | select SND_SOC_ML26124 if I2C | 90 | select SND_SOC_ML26124 if I2C |
90 | select SND_SOC_NAU8825 if I2C | 91 | select SND_SOC_NAU8825 if I2C |
92 | select SND_SOC_HDMI_CODEC | ||
91 | select SND_SOC_PCM1681 if I2C | 93 | select SND_SOC_PCM1681 if I2C |
92 | select SND_SOC_PCM179X_I2C if I2C | 94 | select SND_SOC_PCM179X_I2C if I2C |
93 | select SND_SOC_PCM179X_SPI if SPI_MASTER | 95 | select SND_SOC_PCM179X_SPI if SPI_MASTER |
94 | select SND_SOC_PCM3008 | 96 | select SND_SOC_PCM3008 |
95 | select SND_SOC_PCM3168A_I2C if I2C | 97 | select SND_SOC_PCM3168A_I2C if I2C |
96 | select SND_SOC_PCM3168A_SPI if SPI_MASTER | 98 | select SND_SOC_PCM3168A_SPI if SPI_MASTER |
99 | select SND_SOC_PCM5102A | ||
97 | select SND_SOC_PCM512x_I2C if I2C | 100 | select SND_SOC_PCM512x_I2C if I2C |
98 | select SND_SOC_PCM512x_SPI if SPI_MASTER | 101 | select SND_SOC_PCM512x_SPI if SPI_MASTER |
99 | select SND_SOC_RT286 if I2C | 102 | select SND_SOC_RT286 if I2C |
@@ -124,12 +127,14 @@ config SND_SOC_ALL_CODECS | |||
124 | select SND_SOC_TAS2552 if I2C | 127 | select SND_SOC_TAS2552 if I2C |
125 | select SND_SOC_TAS5086 if I2C | 128 | select SND_SOC_TAS5086 if I2C |
126 | select SND_SOC_TAS571X if I2C | 129 | select SND_SOC_TAS571X if I2C |
130 | select SND_SOC_TAS5720 if I2C | ||
127 | select SND_SOC_TFA9879 if I2C | 131 | select SND_SOC_TFA9879 if I2C |
128 | select SND_SOC_TLV320AIC23_I2C if I2C | 132 | select SND_SOC_TLV320AIC23_I2C if I2C |
129 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | 133 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER |
130 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 134 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
131 | select SND_SOC_TLV320AIC31XX if I2C | 135 | select SND_SOC_TLV320AIC31XX if I2C |
132 | select SND_SOC_TLV320AIC32X4 if I2C | 136 | select SND_SOC_TLV320AIC32X4_I2C if I2C |
137 | select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER | ||
133 | select SND_SOC_TLV320AIC3X if I2C | 138 | select SND_SOC_TLV320AIC3X if I2C |
134 | select SND_SOC_TPA6130A2 if I2C | 139 | select SND_SOC_TPA6130A2 if I2C |
135 | select SND_SOC_TLV320DAC33 if I2C | 140 | select SND_SOC_TLV320DAC33 if I2C |
@@ -365,6 +370,9 @@ config SND_SOC_ALC5623 | |||
365 | config SND_SOC_ALC5632 | 370 | config SND_SOC_ALC5632 |
366 | tristate | 371 | tristate |
367 | 372 | ||
373 | config SND_SOC_BT_SCO | ||
374 | tristate | ||
375 | |||
368 | config SND_SOC_CQ0093VC | 376 | config SND_SOC_CQ0093VC |
369 | tristate | 377 | tristate |
370 | 378 | ||
@@ -471,12 +479,14 @@ config SND_SOC_DA732X | |||
471 | config SND_SOC_DA9055 | 479 | config SND_SOC_DA9055 |
472 | tristate | 480 | tristate |
473 | 481 | ||
474 | config SND_SOC_BT_SCO | ||
475 | tristate | ||
476 | |||
477 | config SND_SOC_DMIC | 482 | config SND_SOC_DMIC |
478 | tristate | 483 | tristate |
479 | 484 | ||
485 | config SND_SOC_HDMI_CODEC | ||
486 | tristate | ||
487 | select SND_PCM_ELD | ||
488 | select SND_PCM_IEC958 | ||
489 | |||
480 | config SND_SOC_ES8328 | 490 | config SND_SOC_ES8328 |
481 | tristate "Everest Semi ES8328 CODEC" | 491 | tristate "Everest Semi ES8328 CODEC" |
482 | 492 | ||
@@ -522,6 +532,9 @@ config SND_SOC_MAX98095 | |||
522 | config SND_SOC_MAX98357A | 532 | config SND_SOC_MAX98357A |
523 | tristate | 533 | tristate |
524 | 534 | ||
535 | config SND_SOC_MAX98371 | ||
536 | tristate | ||
537 | |||
525 | config SND_SOC_MAX9867 | 538 | config SND_SOC_MAX9867 |
526 | tristate | 539 | tristate |
527 | 540 | ||
@@ -575,6 +588,9 @@ config SND_SOC_PCM3168A_SPI | |||
575 | select SND_SOC_PCM3168A | 588 | select SND_SOC_PCM3168A |
576 | select REGMAP_SPI | 589 | select REGMAP_SPI |
577 | 590 | ||
591 | config SND_SOC_PCM5102A | ||
592 | tristate | ||
593 | |||
578 | config SND_SOC_PCM512x | 594 | config SND_SOC_PCM512x |
579 | tristate | 595 | tristate |
580 | 596 | ||
@@ -629,6 +645,7 @@ config SND_SOC_RT5514 | |||
629 | 645 | ||
630 | config SND_SOC_RT5616 | 646 | config SND_SOC_RT5616 |
631 | tristate "Realtek RT5616 CODEC" | 647 | tristate "Realtek RT5616 CODEC" |
648 | depends on I2C | ||
632 | 649 | ||
633 | config SND_SOC_RT5631 | 650 | config SND_SOC_RT5631 |
634 | tristate "Realtek ALC5631/RT5631 CODEC" | 651 | tristate "Realtek ALC5631/RT5631 CODEC" |
@@ -737,9 +754,16 @@ config SND_SOC_TAS5086 | |||
737 | depends on I2C | 754 | depends on I2C |
738 | 755 | ||
739 | config SND_SOC_TAS571X | 756 | config SND_SOC_TAS571X |
740 | tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" | 757 | tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers" |
741 | depends on I2C | 758 | depends on I2C |
742 | 759 | ||
760 | config SND_SOC_TAS5720 | ||
761 | tristate "Texas Instruments TAS5720 Mono Audio amplifier" | ||
762 | depends on I2C | ||
763 | help | ||
764 | Enable support for Texas Instruments TAS5720L/M high-efficiency mono | ||
765 | Class-D audio power amplifiers. | ||
766 | |||
743 | config SND_SOC_TFA9879 | 767 | config SND_SOC_TFA9879 |
744 | tristate "NXP Semiconductors TFA9879 amplifier" | 768 | tristate "NXP Semiconductors TFA9879 amplifier" |
745 | depends on I2C | 769 | depends on I2C |
@@ -769,6 +793,16 @@ config SND_SOC_TLV320AIC31XX | |||
769 | config SND_SOC_TLV320AIC32X4 | 793 | config SND_SOC_TLV320AIC32X4 |
770 | tristate | 794 | tristate |
771 | 795 | ||
796 | config SND_SOC_TLV320AIC32X4_I2C | ||
797 | tristate | ||
798 | depends on I2C | ||
799 | select SND_SOC_TLV320AIC32X4 | ||
800 | |||
801 | config SND_SOC_TLV320AIC32X4_SPI | ||
802 | tristate | ||
803 | depends on SPI_MASTER | ||
804 | select SND_SOC_TLV320AIC32X4 | ||
805 | |||
772 | config SND_SOC_TLV320AIC3X | 806 | config SND_SOC_TLV320AIC3X |
773 | tristate "Texas Instruments TLV320AIC3x CODECs" | 807 | tristate "Texas Instruments TLV320AIC3x CODECs" |
774 | depends on I2C | 808 | depends on I2C |
@@ -909,7 +943,8 @@ config SND_SOC_WM8955 | |||
909 | tristate | 943 | tristate |
910 | 944 | ||
911 | config SND_SOC_WM8960 | 945 | config SND_SOC_WM8960 |
912 | tristate | 946 | tristate "Wolfson Microelectronics WM8960 CODEC" |
947 | depends on I2C | ||
913 | 948 | ||
914 | config SND_SOC_WM8961 | 949 | config SND_SOC_WM8961 |
915 | tristate | 950 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 185a712a7fe7..0f548fd34ca3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -32,6 +32,7 @@ snd-soc-ak4642-objs := ak4642.o | |||
32 | snd-soc-ak4671-objs := ak4671.o | 32 | snd-soc-ak4671-objs := ak4671.o |
33 | snd-soc-ak5386-objs := ak5386.o | 33 | snd-soc-ak5386-objs := ak5386.o |
34 | snd-soc-arizona-objs := arizona.o | 34 | snd-soc-arizona-objs := arizona.o |
35 | snd-soc-bt-sco-objs := bt-sco.o | ||
35 | snd-soc-cq93vc-objs := cq93vc.o | 36 | snd-soc-cq93vc-objs := cq93vc.o |
36 | snd-soc-cs35l32-objs := cs35l32.o | 37 | snd-soc-cs35l32-objs := cs35l32.o |
37 | snd-soc-cs42l51-objs := cs42l51.o | 38 | snd-soc-cs42l51-objs := cs42l51.o |
@@ -55,7 +56,6 @@ snd-soc-da7218-objs := da7218.o | |||
55 | snd-soc-da7219-objs := da7219.o da7219-aad.o | 56 | snd-soc-da7219-objs := da7219.o da7219-aad.o |
56 | snd-soc-da732x-objs := da732x.o | 57 | snd-soc-da732x-objs := da732x.o |
57 | snd-soc-da9055-objs := da9055.o | 58 | snd-soc-da9055-objs := da9055.o |
58 | snd-soc-bt-sco-objs := bt-sco.o | ||
59 | snd-soc-dmic-objs := dmic.o | 59 | snd-soc-dmic-objs := dmic.o |
60 | snd-soc-es8328-objs := es8328.o | 60 | snd-soc-es8328-objs := es8328.o |
61 | snd-soc-es8328-i2c-objs := es8328-i2c.o | 61 | snd-soc-es8328-i2c-objs := es8328-i2c.o |
@@ -74,6 +74,7 @@ snd-soc-max98088-objs := max98088.o | |||
74 | snd-soc-max98090-objs := max98090.o | 74 | snd-soc-max98090-objs := max98090.o |
75 | snd-soc-max98095-objs := max98095.o | 75 | snd-soc-max98095-objs := max98095.o |
76 | snd-soc-max98357a-objs := max98357a.o | 76 | snd-soc-max98357a-objs := max98357a.o |
77 | snd-soc-max98371-objs := max98371.o | ||
77 | snd-soc-max9867-objs := max9867.o | 78 | snd-soc-max9867-objs := max9867.o |
78 | snd-soc-max98925-objs := max98925.o | 79 | snd-soc-max98925-objs := max98925.o |
79 | snd-soc-max98926-objs := max98926.o | 80 | snd-soc-max98926-objs := max98926.o |
@@ -81,6 +82,7 @@ snd-soc-max9850-objs := max9850.o | |||
81 | snd-soc-mc13783-objs := mc13783.o | 82 | snd-soc-mc13783-objs := mc13783.o |
82 | snd-soc-ml26124-objs := ml26124.o | 83 | snd-soc-ml26124-objs := ml26124.o |
83 | snd-soc-nau8825-objs := nau8825.o | 84 | snd-soc-nau8825-objs := nau8825.o |
85 | snd-soc-hdmi-codec-objs := hdmi-codec.o | ||
84 | snd-soc-pcm1681-objs := pcm1681.o | 86 | snd-soc-pcm1681-objs := pcm1681.o |
85 | snd-soc-pcm179x-codec-objs := pcm179x.o | 87 | snd-soc-pcm179x-codec-objs := pcm179x.o |
86 | snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o | 88 | snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o |
@@ -89,6 +91,7 @@ snd-soc-pcm3008-objs := pcm3008.o | |||
89 | snd-soc-pcm3168a-objs := pcm3168a.o | 91 | snd-soc-pcm3168a-objs := pcm3168a.o |
90 | snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o | 92 | snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o |
91 | snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o | 93 | snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o |
94 | snd-soc-pcm5102a-objs := pcm5102a.o | ||
92 | snd-soc-pcm512x-objs := pcm512x.o | 95 | snd-soc-pcm512x-objs := pcm512x.o |
93 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | 96 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o |
94 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | 97 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o |
@@ -129,6 +132,7 @@ snd-soc-stac9766-objs := stac9766.o | |||
129 | snd-soc-sti-sas-objs := sti-sas.o | 132 | snd-soc-sti-sas-objs := sti-sas.o |
130 | snd-soc-tas5086-objs := tas5086.o | 133 | snd-soc-tas5086-objs := tas5086.o |
131 | snd-soc-tas571x-objs := tas571x.o | 134 | snd-soc-tas571x-objs := tas571x.o |
135 | snd-soc-tas5720-objs := tas5720.o | ||
132 | snd-soc-tfa9879-objs := tfa9879.o | 136 | snd-soc-tfa9879-objs := tfa9879.o |
133 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 137 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
134 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | 138 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o |
@@ -136,6 +140,8 @@ snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o | |||
136 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 140 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
137 | snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o | 141 | snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o |
138 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | 142 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o |
143 | snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o | ||
144 | snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o | ||
139 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 145 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
140 | snd-soc-tlv320dac33-objs := tlv320dac33.o | 146 | snd-soc-tlv320dac33-objs := tlv320dac33.o |
141 | snd-soc-ts3a227e-objs := ts3a227e.o | 147 | snd-soc-ts3a227e-objs := ts3a227e.o |
@@ -241,6 +247,7 @@ obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o | |||
241 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | 247 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o |
242 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o | 248 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o |
243 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o | 249 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o |
250 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o | ||
244 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 251 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
245 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o | 252 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o |
246 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | 253 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o |
@@ -264,7 +271,6 @@ obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o | |||
264 | obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o | 271 | obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o |
265 | obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o | 272 | obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o |
266 | obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o | 273 | obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o |
267 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o | ||
268 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o | 274 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o |
269 | obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o | 275 | obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o |
270 | obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o | 276 | obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o |
@@ -290,6 +296,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o | |||
290 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o | 296 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o |
291 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o | 297 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o |
292 | obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o | 298 | obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o |
299 | obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o | ||
293 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o | 300 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o |
294 | obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o | 301 | obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o |
295 | obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o | 302 | obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o |
@@ -298,6 +305,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | |||
298 | obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o | 305 | obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o |
299 | obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o | 306 | obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o |
300 | obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o | 307 | obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o |
308 | obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o | ||
301 | obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | 309 | obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o |
302 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | 310 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o |
303 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | 311 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o |
@@ -335,6 +343,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o | |||
335 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o | 343 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o |
336 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 344 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
337 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o | 345 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o |
346 | obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o | ||
338 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o | 347 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o |
339 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 348 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
340 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | 349 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o |
@@ -342,6 +351,8 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o | |||
342 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 351 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
343 | obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o | 352 | obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o |
344 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o | 353 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o |
354 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o | ||
355 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o | ||
345 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 356 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
346 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o | 357 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o |
347 | obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o | 358 | obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index cda27c22812a..4d8b9e49e8d6 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -560,6 +560,7 @@ static const struct regmap_config ak4642_regmap = { | |||
560 | .max_register = FIL1_3, | 560 | .max_register = FIL1_3, |
561 | .reg_defaults = ak4642_reg, | 561 | .reg_defaults = ak4642_reg, |
562 | .num_reg_defaults = NUM_AK4642_REG_DEFAULTS, | 562 | .num_reg_defaults = NUM_AK4642_REG_DEFAULTS, |
563 | .cache_type = REGCACHE_RBTREE, | ||
563 | }; | 564 | }; |
564 | 565 | ||
565 | static const struct regmap_config ak4643_regmap = { | 566 | static const struct regmap_config ak4643_regmap = { |
@@ -568,6 +569,7 @@ static const struct regmap_config ak4643_regmap = { | |||
568 | .max_register = SPK_MS, | 569 | .max_register = SPK_MS, |
569 | .reg_defaults = ak4643_reg, | 570 | .reg_defaults = ak4643_reg, |
570 | .num_reg_defaults = ARRAY_SIZE(ak4643_reg), | 571 | .num_reg_defaults = ARRAY_SIZE(ak4643_reg), |
572 | .cache_type = REGCACHE_RBTREE, | ||
571 | }; | 573 | }; |
572 | 574 | ||
573 | static const struct regmap_config ak4648_regmap = { | 575 | static const struct regmap_config ak4648_regmap = { |
@@ -576,6 +578,7 @@ static const struct regmap_config ak4648_regmap = { | |||
576 | .max_register = EQ_FBEQE, | 578 | .max_register = EQ_FBEQE, |
577 | .reg_defaults = ak4648_reg, | 579 | .reg_defaults = ak4648_reg, |
578 | .num_reg_defaults = ARRAY_SIZE(ak4648_reg), | 580 | .num_reg_defaults = ARRAY_SIZE(ak4648_reg), |
581 | .cache_type = REGCACHE_RBTREE, | ||
579 | }; | 582 | }; |
580 | 583 | ||
581 | static const struct ak4642_drvdata ak4642_drvdata = { | 584 | static const struct ak4642_drvdata ak4642_drvdata = { |
@@ -608,9 +611,7 @@ static struct clk *ak4642_of_parse_mcko(struct device *dev) | |||
608 | 611 | ||
609 | of_property_read_string(np, "clock-output-names", &clk_name); | 612 | of_property_read_string(np, "clock-output-names", &clk_name); |
610 | 613 | ||
611 | clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, | 614 | clk = clk_register_fixed_rate(dev, clk_name, parent_clk_name, 0, rate); |
612 | (parent_clk_name) ? 0 : CLK_IS_ROOT, | ||
613 | rate); | ||
614 | if (!IS_ERR(clk)) | 615 | if (!IS_ERR(clk)) |
615 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | 616 | of_clk_add_provider(np, of_clk_src_simple_get, clk); |
616 | 617 | ||
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 92d22a018d68..664a8c044ffb 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -221,6 +221,8 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
221 | 221 | ||
222 | switch (arizona->type) { | 222 | switch (arizona->type) { |
223 | case WM8997: | 223 | case WM8997: |
224 | case CS47L24: | ||
225 | case WM1831: | ||
224 | break; | 226 | break; |
225 | default: | 227 | default: |
226 | ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1); | 228 | ret = snd_soc_dapm_new_controls(dapm, &arizona_spkr, 1); |
@@ -249,6 +251,18 @@ int arizona_init_spk(struct snd_soc_codec *codec) | |||
249 | } | 251 | } |
250 | EXPORT_SYMBOL_GPL(arizona_init_spk); | 252 | EXPORT_SYMBOL_GPL(arizona_init_spk); |
251 | 253 | ||
254 | int arizona_free_spk(struct snd_soc_codec *codec) | ||
255 | { | ||
256 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
257 | struct arizona *arizona = priv->arizona; | ||
258 | |||
259 | arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona); | ||
260 | arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | EXPORT_SYMBOL_GPL(arizona_free_spk); | ||
265 | |||
252 | static const struct snd_soc_dapm_route arizona_mono_routes[] = { | 266 | static const struct snd_soc_dapm_route arizona_mono_routes[] = { |
253 | { "OUT1R", NULL, "OUT1L" }, | 267 | { "OUT1R", NULL, "OUT1L" }, |
254 | { "OUT2R", NULL, "OUT2L" }, | 268 | { "OUT2R", NULL, "OUT2L" }, |
@@ -1122,7 +1136,6 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w, | |||
1122 | int event) | 1136 | int event) |
1123 | { | 1137 | { |
1124 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 1138 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
1125 | unsigned int mask = 0x3 << w->shift; | ||
1126 | unsigned int val; | 1139 | unsigned int val; |
1127 | 1140 | ||
1128 | switch (event) { | 1141 | switch (event) { |
@@ -1136,7 +1149,7 @@ int arizona_anc_ev(struct snd_soc_dapm_widget *w, | |||
1136 | return 0; | 1149 | return 0; |
1137 | } | 1150 | } |
1138 | 1151 | ||
1139 | snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val); | 1152 | snd_soc_write(codec, ARIZONA_CLOCK_CONTROL, val); |
1140 | 1153 | ||
1141 | return 0; | 1154 | return 0; |
1142 | } | 1155 | } |
@@ -2035,7 +2048,21 @@ static int arizona_calc_fratio(struct arizona_fll *fll, | |||
2035 | init_ratio, Fref, refdiv); | 2048 | init_ratio, Fref, refdiv); |
2036 | 2049 | ||
2037 | while (div <= ARIZONA_FLL_MAX_REFDIV) { | 2050 | while (div <= ARIZONA_FLL_MAX_REFDIV) { |
2038 | for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; | 2051 | /* start from init_ratio because this may already give a |
2052 | * fractional N.K | ||
2053 | */ | ||
2054 | for (ratio = init_ratio; ratio > 0; ratio--) { | ||
2055 | if (target % (ratio * Fref)) { | ||
2056 | cfg->refdiv = refdiv; | ||
2057 | cfg->fratio = ratio - 1; | ||
2058 | arizona_fll_dbg(fll, | ||
2059 | "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n", | ||
2060 | Fref, refdiv, div, ratio); | ||
2061 | return ratio; | ||
2062 | } | ||
2063 | } | ||
2064 | |||
2065 | for (ratio = init_ratio + 1; ratio <= ARIZONA_FLL_MAX_FRATIO; | ||
2039 | ratio++) { | 2066 | ratio++) { |
2040 | if ((ARIZONA_FLL_VCO_CORNER / 2) / | 2067 | if ((ARIZONA_FLL_VCO_CORNER / 2) / |
2041 | (fll->vco_mult * ratio) < Fref) { | 2068 | (fll->vco_mult * ratio) < Fref) { |
@@ -2061,17 +2088,6 @@ static int arizona_calc_fratio(struct arizona_fll *fll, | |||
2061 | } | 2088 | } |
2062 | } | 2089 | } |
2063 | 2090 | ||
2064 | for (ratio = init_ratio - 1; ratio > 0; ratio--) { | ||
2065 | if (target % (ratio * Fref)) { | ||
2066 | cfg->refdiv = refdiv; | ||
2067 | cfg->fratio = ratio - 1; | ||
2068 | arizona_fll_dbg(fll, | ||
2069 | "pseudo: found fref=%u refdiv=%d(%d) ratio=%d\n", | ||
2070 | Fref, refdiv, div, ratio); | ||
2071 | return ratio; | ||
2072 | } | ||
2073 | } | ||
2074 | |||
2075 | div *= 2; | 2091 | div *= 2; |
2076 | Fref /= 2; | 2092 | Fref /= 2; |
2077 | refdiv++; | 2093 | refdiv++; |
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 1ea8e4ecf8d4..ce0531b8c632 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -307,6 +307,8 @@ extern int arizona_init_spk(struct snd_soc_codec *codec); | |||
307 | extern int arizona_init_gpio(struct snd_soc_codec *codec); | 307 | extern int arizona_init_gpio(struct snd_soc_codec *codec); |
308 | extern int arizona_init_mono(struct snd_soc_codec *codec); | 308 | extern int arizona_init_mono(struct snd_soc_codec *codec); |
309 | 309 | ||
310 | extern int arizona_free_spk(struct snd_soc_codec *codec); | ||
311 | |||
310 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); | 312 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); |
311 | 313 | ||
312 | int arizona_set_output_mode(struct snd_soc_codec *codec, int output, | 314 | int arizona_set_output_mode(struct snd_soc_codec *codec, int output, |
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 44c30fe3e315..287d13740be4 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c | |||
@@ -274,7 +274,9 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, | |||
274 | if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0) | 274 | if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0) |
275 | pdata->sdout_share = val; | 275 | pdata->sdout_share = val; |
276 | 276 | ||
277 | of_property_read_u32(np, "cirrus,boost-manager", &val); | 277 | if (of_property_read_u32(np, "cirrus,boost-manager", &val)) |
278 | val = -1u; | ||
279 | |||
278 | switch (val) { | 280 | switch (val) { |
279 | case CS35L32_BOOST_MGR_AUTO: | 281 | case CS35L32_BOOST_MGR_AUTO: |
280 | case CS35L32_BOOST_MGR_AUTO_AUDIO: | 282 | case CS35L32_BOOST_MGR_AUTO_AUDIO: |
@@ -282,13 +284,15 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, | |||
282 | case CS35L32_BOOST_MGR_FIXED: | 284 | case CS35L32_BOOST_MGR_FIXED: |
283 | pdata->boost_mng = val; | 285 | pdata->boost_mng = val; |
284 | break; | 286 | break; |
287 | case -1u: | ||
285 | default: | 288 | default: |
286 | dev_err(&i2c_client->dev, | 289 | dev_err(&i2c_client->dev, |
287 | "Wrong cirrus,boost-manager DT value %d\n", val); | 290 | "Wrong cirrus,boost-manager DT value %d\n", val); |
288 | pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS; | 291 | pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS; |
289 | } | 292 | } |
290 | 293 | ||
291 | of_property_read_u32(np, "cirrus,sdout-datacfg", &val); | 294 | if (of_property_read_u32(np, "cirrus,sdout-datacfg", &val)) |
295 | val = -1u; | ||
292 | switch (val) { | 296 | switch (val) { |
293 | case CS35L32_DATA_CFG_LR_VP: | 297 | case CS35L32_DATA_CFG_LR_VP: |
294 | case CS35L32_DATA_CFG_LR_STAT: | 298 | case CS35L32_DATA_CFG_LR_STAT: |
@@ -296,13 +300,15 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, | |||
296 | case CS35L32_DATA_CFG_LR_VPSTAT: | 300 | case CS35L32_DATA_CFG_LR_VPSTAT: |
297 | pdata->sdout_datacfg = val; | 301 | pdata->sdout_datacfg = val; |
298 | break; | 302 | break; |
303 | case -1u: | ||
299 | default: | 304 | default: |
300 | dev_err(&i2c_client->dev, | 305 | dev_err(&i2c_client->dev, |
301 | "Wrong cirrus,sdout-datacfg DT value %d\n", val); | 306 | "Wrong cirrus,sdout-datacfg DT value %d\n", val); |
302 | pdata->sdout_datacfg = CS35L32_DATA_CFG_LR; | 307 | pdata->sdout_datacfg = CS35L32_DATA_CFG_LR; |
303 | } | 308 | } |
304 | 309 | ||
305 | of_property_read_u32(np, "cirrus,battery-threshold", &val); | 310 | if (of_property_read_u32(np, "cirrus,battery-threshold", &val)) |
311 | val = -1u; | ||
306 | switch (val) { | 312 | switch (val) { |
307 | case CS35L32_BATT_THRESH_3_1V: | 313 | case CS35L32_BATT_THRESH_3_1V: |
308 | case CS35L32_BATT_THRESH_3_2V: | 314 | case CS35L32_BATT_THRESH_3_2V: |
@@ -310,13 +316,15 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, | |||
310 | case CS35L32_BATT_THRESH_3_4V: | 316 | case CS35L32_BATT_THRESH_3_4V: |
311 | pdata->batt_thresh = val; | 317 | pdata->batt_thresh = val; |
312 | break; | 318 | break; |
319 | case -1u: | ||
313 | default: | 320 | default: |
314 | dev_err(&i2c_client->dev, | 321 | dev_err(&i2c_client->dev, |
315 | "Wrong cirrus,battery-threshold DT value %d\n", val); | 322 | "Wrong cirrus,battery-threshold DT value %d\n", val); |
316 | pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V; | 323 | pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V; |
317 | } | 324 | } |
318 | 325 | ||
319 | of_property_read_u32(np, "cirrus,battery-recovery", &val); | 326 | if (of_property_read_u32(np, "cirrus,battery-recovery", &val)) |
327 | val = -1u; | ||
320 | switch (val) { | 328 | switch (val) { |
321 | case CS35L32_BATT_RECOV_3_1V: | 329 | case CS35L32_BATT_RECOV_3_1V: |
322 | case CS35L32_BATT_RECOV_3_2V: | 330 | case CS35L32_BATT_RECOV_3_2V: |
@@ -326,6 +334,7 @@ static int cs35l32_handle_of_data(struct i2c_client *i2c_client, | |||
326 | case CS35L32_BATT_RECOV_3_6V: | 334 | case CS35L32_BATT_RECOV_3_6V: |
327 | pdata->batt_recov = val; | 335 | pdata->batt_recov = val; |
328 | break; | 336 | break; |
337 | case -1u: | ||
329 | default: | 338 | default: |
330 | dev_err(&i2c_client->dev, | 339 | dev_err(&i2c_client->dev, |
331 | "Wrong cirrus,battery-recovery DT value %d\n", val); | 340 | "Wrong cirrus,battery-recovery DT value %d\n", val); |
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 7cd5f769bb61..eec1ff853b98 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c | |||
@@ -56,7 +56,7 @@ struct cs42l56_private { | |||
56 | u8 iface; | 56 | u8 iface; |
57 | u8 iface_fmt; | 57 | u8 iface_fmt; |
58 | u8 iface_inv; | 58 | u8 iface_inv; |
59 | #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) | 59 | #if IS_ENABLED(CONFIG_INPUT) |
60 | struct input_dev *beep; | 60 | struct input_dev *beep; |
61 | struct work_struct beep_work; | 61 | struct work_struct beep_work; |
62 | int beep_rate; | 62 | int beep_rate; |
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 576087bda330..5ec5a682d186 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c | |||
@@ -807,6 +807,9 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { | |||
807 | { "IN2L PGA", NULL, "IN2L" }, | 807 | { "IN2L PGA", NULL, "IN2L" }, |
808 | { "IN2R PGA", NULL, "IN2R" }, | 808 | { "IN2R PGA", NULL, "IN2R" }, |
809 | 809 | ||
810 | { "Audio Trace DSP", NULL, "DSP2" }, | ||
811 | { "Audio Trace DSP", NULL, "SYSCLK" }, | ||
812 | |||
810 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), | 813 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), |
811 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), | 814 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), |
812 | 815 | ||
@@ -1016,6 +1019,27 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { | |||
1016 | .formats = CS47L24_FORMATS, | 1019 | .formats = CS47L24_FORMATS, |
1017 | }, | 1020 | }, |
1018 | }, | 1021 | }, |
1022 | { | ||
1023 | .name = "cs47l24-cpu-trace", | ||
1024 | .capture = { | ||
1025 | .stream_name = "Audio Trace CPU", | ||
1026 | .channels_min = 1, | ||
1027 | .channels_max = 6, | ||
1028 | .rates = CS47L24_RATES, | ||
1029 | .formats = CS47L24_FORMATS, | ||
1030 | }, | ||
1031 | .compress_new = snd_soc_new_compress, | ||
1032 | }, | ||
1033 | { | ||
1034 | .name = "cs47l24-dsp-trace", | ||
1035 | .capture = { | ||
1036 | .stream_name = "Audio Trace DSP", | ||
1037 | .channels_min = 1, | ||
1038 | .channels_max = 6, | ||
1039 | .rates = CS47L24_RATES, | ||
1040 | .formats = CS47L24_FORMATS, | ||
1041 | }, | ||
1042 | }, | ||
1019 | }; | 1043 | }; |
1020 | 1044 | ||
1021 | static int cs47l24_open(struct snd_compr_stream *stream) | 1045 | static int cs47l24_open(struct snd_compr_stream *stream) |
@@ -1027,6 +1051,8 @@ static int cs47l24_open(struct snd_compr_stream *stream) | |||
1027 | 1051 | ||
1028 | if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) { | 1052 | if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-voicectrl") == 0) { |
1029 | n_adsp = 2; | 1053 | n_adsp = 2; |
1054 | } else if (strcmp(rtd->codec_dai->name, "cs47l24-dsp-trace") == 0) { | ||
1055 | n_adsp = 1; | ||
1030 | } else { | 1056 | } else { |
1031 | dev_err(arizona->dev, | 1057 | dev_err(arizona->dev, |
1032 | "No suitable compressed stream for DAI '%s'\n", | 1058 | "No suitable compressed stream for DAI '%s'\n", |
@@ -1041,10 +1067,16 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) | |||
1041 | { | 1067 | { |
1042 | struct cs47l24_priv *priv = data; | 1068 | struct cs47l24_priv *priv = data; |
1043 | struct arizona *arizona = priv->core.arizona; | 1069 | struct arizona *arizona = priv->core.arizona; |
1044 | int ret; | 1070 | int serviced = 0; |
1071 | int i, ret; | ||
1072 | |||
1073 | for (i = 1; i <= 2; ++i) { | ||
1074 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); | ||
1075 | if (ret != -ENODEV) | ||
1076 | serviced++; | ||
1077 | } | ||
1045 | 1078 | ||
1046 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[2]); | 1079 | if (!serviced) { |
1047 | if (ret == -ENODEV) { | ||
1048 | dev_err(arizona->dev, "Spurious compressed data IRQ\n"); | 1080 | dev_err(arizona->dev, "Spurious compressed data IRQ\n"); |
1049 | return IRQ_NONE; | 1081 | return IRQ_NONE; |
1050 | } | 1082 | } |
@@ -1108,6 +1140,9 @@ static int cs47l24_codec_remove(struct snd_soc_codec *codec) | |||
1108 | priv->core.arizona->dapm = NULL; | 1140 | priv->core.arizona->dapm = NULL; |
1109 | 1141 | ||
1110 | arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); | 1142 | arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); |
1143 | |||
1144 | arizona_free_spk(codec); | ||
1145 | |||
1111 | return 0; | 1146 | return 0; |
1112 | } | 1147 | } |
1113 | 1148 | ||
@@ -1157,6 +1192,7 @@ static struct snd_compr_ops cs47l24_compr_ops = { | |||
1157 | static struct snd_soc_platform_driver cs47l24_compr_platform = { | 1192 | static struct snd_soc_platform_driver cs47l24_compr_platform = { |
1158 | .compr_ops = &cs47l24_compr_ops, | 1193 | .compr_ops = &cs47l24_compr_ops, |
1159 | }; | 1194 | }; |
1195 | |||
1160 | static int cs47l24_probe(struct platform_device *pdev) | 1196 | static int cs47l24_probe(struct platform_device *pdev) |
1161 | { | 1197 | { |
1162 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | 1198 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); |
@@ -1225,9 +1261,9 @@ static int cs47l24_probe(struct platform_device *pdev) | |||
1225 | dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); | 1261 | dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); |
1226 | return ret; | 1262 | return ret; |
1227 | } | 1263 | } |
1264 | |||
1228 | ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, | 1265 | ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, |
1229 | cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); | 1266 | cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); |
1230 | |||
1231 | if (ret < 0) { | 1267 | if (ret < 0) { |
1232 | dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); | 1268 | dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); |
1233 | snd_soc_unregister_platform(&pdev->dev); | 1269 | snd_soc_unregister_platform(&pdev->dev); |
@@ -1238,10 +1274,15 @@ static int cs47l24_probe(struct platform_device *pdev) | |||
1238 | 1274 | ||
1239 | static int cs47l24_remove(struct platform_device *pdev) | 1275 | static int cs47l24_remove(struct platform_device *pdev) |
1240 | { | 1276 | { |
1277 | struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev); | ||
1278 | |||
1241 | snd_soc_unregister_platform(&pdev->dev); | 1279 | snd_soc_unregister_platform(&pdev->dev); |
1242 | snd_soc_unregister_codec(&pdev->dev); | 1280 | snd_soc_unregister_codec(&pdev->dev); |
1243 | pm_runtime_disable(&pdev->dev); | 1281 | pm_runtime_disable(&pdev->dev); |
1244 | 1282 | ||
1283 | wm_adsp2_remove(&cs47l24->core.adsp[1]); | ||
1284 | wm_adsp2_remove(&cs47l24->core.adsp[2]); | ||
1285 | |||
1245 | return 0; | 1286 | return 0; |
1246 | } | 1287 | } |
1247 | 1288 | ||
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 7278f93460c1..e5527bc570ae 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c | |||
@@ -726,6 +726,68 @@ static const struct snd_kcontrol_new da7213_dapm_mixoutr_controls[] = { | |||
726 | 726 | ||
727 | 727 | ||
728 | /* | 728 | /* |
729 | * DAPM Events | ||
730 | */ | ||
731 | |||
732 | static int da7213_dai_event(struct snd_soc_dapm_widget *w, | ||
733 | struct snd_kcontrol *kcontrol, int event) | ||
734 | { | ||
735 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
736 | struct da7213_priv *da7213 = snd_soc_codec_get_drvdata(codec); | ||
737 | u8 pll_ctrl, pll_status; | ||
738 | int i = 0; | ||
739 | bool srm_lock = false; | ||
740 | |||
741 | switch (event) { | ||
742 | case SND_SOC_DAPM_PRE_PMU: | ||
743 | /* Enable DAI clks for master mode */ | ||
744 | if (da7213->master) | ||
745 | snd_soc_update_bits(codec, DA7213_DAI_CLK_MODE, | ||
746 | DA7213_DAI_CLK_EN_MASK, | ||
747 | DA7213_DAI_CLK_EN_MASK); | ||
748 | |||
749 | /* PC synchronised to DAI */ | ||
750 | snd_soc_update_bits(codec, DA7213_PC_COUNT, | ||
751 | DA7213_PC_FREERUN_MASK, 0); | ||
752 | |||
753 | /* Slave mode, if SRM not enabled no need for status checks */ | ||
754 | pll_ctrl = snd_soc_read(codec, DA7213_PLL_CTRL); | ||
755 | if (!(pll_ctrl & DA7213_PLL_SRM_EN)) | ||
756 | return 0; | ||
757 | |||
758 | /* Check SRM has locked */ | ||
759 | do { | ||
760 | pll_status = snd_soc_read(codec, DA7213_PLL_STATUS); | ||
761 | if (pll_status & DA7219_PLL_SRM_LOCK) { | ||
762 | srm_lock = true; | ||
763 | } else { | ||
764 | ++i; | ||
765 | msleep(50); | ||
766 | } | ||
767 | } while ((i < DA7213_SRM_CHECK_RETRIES) & (!srm_lock)); | ||
768 | |||
769 | if (!srm_lock) | ||
770 | dev_warn(codec->dev, "SRM failed to lock\n"); | ||
771 | |||
772 | return 0; | ||
773 | case SND_SOC_DAPM_POST_PMD: | ||
774 | /* PC free-running */ | ||
775 | snd_soc_update_bits(codec, DA7213_PC_COUNT, | ||
776 | DA7213_PC_FREERUN_MASK, | ||
777 | DA7213_PC_FREERUN_MASK); | ||
778 | |||
779 | /* Disable DAI clks if in master mode */ | ||
780 | if (da7213->master) | ||
781 | snd_soc_update_bits(codec, DA7213_DAI_CLK_MODE, | ||
782 | DA7213_DAI_CLK_EN_MASK, 0); | ||
783 | return 0; | ||
784 | default: | ||
785 | return -EINVAL; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | |||
790 | /* | ||
729 | * DAPM widgets | 791 | * DAPM widgets |
730 | */ | 792 | */ |
731 | 793 | ||
@@ -736,7 +798,8 @@ static const struct snd_soc_dapm_widget da7213_dapm_widgets[] = { | |||
736 | 798 | ||
737 | /* Use a supply here as this controls both input & output DAIs */ | 799 | /* Use a supply here as this controls both input & output DAIs */ |
738 | SND_SOC_DAPM_SUPPLY("DAI", DA7213_DAI_CTRL, DA7213_DAI_EN_SHIFT, | 800 | SND_SOC_DAPM_SUPPLY("DAI", DA7213_DAI_CTRL, DA7213_DAI_EN_SHIFT, |
739 | DA7213_NO_INVERT, NULL, 0), | 801 | DA7213_NO_INVERT, da7213_dai_event, |
802 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
740 | 803 | ||
741 | /* | 804 | /* |
742 | * Input | 805 | * Input |
@@ -1143,11 +1206,9 @@ static int da7213_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1143 | /* Set master/slave mode */ | 1206 | /* Set master/slave mode */ |
1144 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1207 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
1145 | case SND_SOC_DAIFMT_CBM_CFM: | 1208 | case SND_SOC_DAIFMT_CBM_CFM: |
1146 | dai_clk_mode |= DA7213_DAI_CLK_EN_MASTER_MODE; | ||
1147 | da7213->master = true; | 1209 | da7213->master = true; |
1148 | break; | 1210 | break; |
1149 | case SND_SOC_DAIFMT_CBS_CFS: | 1211 | case SND_SOC_DAIFMT_CBS_CFS: |
1150 | dai_clk_mode |= DA7213_DAI_CLK_EN_SLAVE_MODE; | ||
1151 | da7213->master = false; | 1212 | da7213->master = false; |
1152 | break; | 1213 | break; |
1153 | default: | 1214 | default: |
@@ -1281,28 +1342,28 @@ static int da7213_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | |||
1281 | pll_ctrl = 0; | 1342 | pll_ctrl = 0; |
1282 | 1343 | ||
1283 | /* Workout input divider based on MCLK rate */ | 1344 | /* Workout input divider based on MCLK rate */ |
1284 | if ((da7213->mclk_rate == 32768) && (source == DA7213_SYSCLK_PLL)) { | 1345 | if (da7213->mclk_rate == 32768) { |
1285 | /* 32KHz PLL Mode */ | 1346 | /* 32KHz PLL Mode */ |
1286 | indiv_bits = DA7213_PLL_INDIV_10_20_MHZ; | 1347 | indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ; |
1287 | indiv = DA7213_PLL_INDIV_10_20_MHZ_VAL; | 1348 | indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL; |
1288 | freq_ref = 3750000; | 1349 | freq_ref = 3750000; |
1289 | pll_ctrl |= DA7213_PLL_32K_MODE; | 1350 | pll_ctrl |= DA7213_PLL_32K_MODE; |
1290 | } else { | 1351 | } else { |
1291 | /* 5 - 54MHz MCLK */ | 1352 | /* 5 - 54MHz MCLK */ |
1292 | if (da7213->mclk_rate < 5000000) { | 1353 | if (da7213->mclk_rate < 5000000) { |
1293 | goto pll_err; | 1354 | goto pll_err; |
1294 | } else if (da7213->mclk_rate <= 10000000) { | 1355 | } else if (da7213->mclk_rate <= 9000000) { |
1295 | indiv_bits = DA7213_PLL_INDIV_5_10_MHZ; | 1356 | indiv_bits = DA7213_PLL_INDIV_5_TO_9_MHZ; |
1296 | indiv = DA7213_PLL_INDIV_5_10_MHZ_VAL; | 1357 | indiv = DA7213_PLL_INDIV_5_TO_9_MHZ_VAL; |
1297 | } else if (da7213->mclk_rate <= 20000000) { | 1358 | } else if (da7213->mclk_rate <= 18000000) { |
1298 | indiv_bits = DA7213_PLL_INDIV_10_20_MHZ; | 1359 | indiv_bits = DA7213_PLL_INDIV_9_TO_18_MHZ; |
1299 | indiv = DA7213_PLL_INDIV_10_20_MHZ_VAL; | 1360 | indiv = DA7213_PLL_INDIV_9_TO_18_MHZ_VAL; |
1300 | } else if (da7213->mclk_rate <= 40000000) { | 1361 | } else if (da7213->mclk_rate <= 36000000) { |
1301 | indiv_bits = DA7213_PLL_INDIV_20_40_MHZ; | 1362 | indiv_bits = DA7213_PLL_INDIV_18_TO_36_MHZ; |
1302 | indiv = DA7213_PLL_INDIV_20_40_MHZ_VAL; | 1363 | indiv = DA7213_PLL_INDIV_18_TO_36_MHZ_VAL; |
1303 | } else if (da7213->mclk_rate <= 54000000) { | 1364 | } else if (da7213->mclk_rate <= 54000000) { |
1304 | indiv_bits = DA7213_PLL_INDIV_40_54_MHZ; | 1365 | indiv_bits = DA7213_PLL_INDIV_36_TO_54_MHZ; |
1305 | indiv = DA7213_PLL_INDIV_40_54_MHZ_VAL; | 1366 | indiv = DA7213_PLL_INDIV_36_TO_54_MHZ_VAL; |
1306 | } else { | 1367 | } else { |
1307 | goto pll_err; | 1368 | goto pll_err; |
1308 | } | 1369 | } |
@@ -1547,6 +1608,10 @@ static int da7213_probe(struct snd_soc_codec *codec) | |||
1547 | /* Default to using SRM for slave mode */ | 1608 | /* Default to using SRM for slave mode */ |
1548 | da7213->srm_en = true; | 1609 | da7213->srm_en = true; |
1549 | 1610 | ||
1611 | /* Default PC counter to free-running */ | ||
1612 | snd_soc_update_bits(codec, DA7213_PC_COUNT, DA7213_PC_FREERUN_MASK, | ||
1613 | DA7213_PC_FREERUN_MASK); | ||
1614 | |||
1550 | /* Enable all Gain Ramps */ | 1615 | /* Enable all Gain Ramps */ |
1551 | snd_soc_update_bits(codec, DA7213_AUX_L_CTRL, | 1616 | snd_soc_update_bits(codec, DA7213_AUX_L_CTRL, |
1552 | DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); | 1617 | DA7213_GAIN_RAMP_EN, DA7213_GAIN_RAMP_EN); |
diff --git a/sound/soc/codecs/da7213.h b/sound/soc/codecs/da7213.h index 030fd691b076..fbb7a356a501 100644 --- a/sound/soc/codecs/da7213.h +++ b/sound/soc/codecs/da7213.h | |||
@@ -142,6 +142,9 @@ | |||
142 | * Bit fields | 142 | * Bit fields |
143 | */ | 143 | */ |
144 | 144 | ||
145 | /* DA7213_PLL_STATUS = 0x03 */ | ||
146 | #define DA7219_PLL_SRM_LOCK (0x1 << 1) | ||
147 | |||
145 | /* DA7213_SR = 0x22 */ | 148 | /* DA7213_SR = 0x22 */ |
146 | #define DA7213_SR_8000 (0x1 << 0) | 149 | #define DA7213_SR_8000 (0x1 << 0) |
147 | #define DA7213_SR_11025 (0x2 << 0) | 150 | #define DA7213_SR_11025 (0x2 << 0) |
@@ -160,10 +163,10 @@ | |||
160 | #define DA7213_VMID_EN (0x1 << 7) | 163 | #define DA7213_VMID_EN (0x1 << 7) |
161 | 164 | ||
162 | /* DA7213_PLL_CTRL = 0x27 */ | 165 | /* DA7213_PLL_CTRL = 0x27 */ |
163 | #define DA7213_PLL_INDIV_5_10_MHZ (0x0 << 2) | 166 | #define DA7213_PLL_INDIV_5_TO_9_MHZ (0x0 << 2) |
164 | #define DA7213_PLL_INDIV_10_20_MHZ (0x1 << 2) | 167 | #define DA7213_PLL_INDIV_9_TO_18_MHZ (0x1 << 2) |
165 | #define DA7213_PLL_INDIV_20_40_MHZ (0x2 << 2) | 168 | #define DA7213_PLL_INDIV_18_TO_36_MHZ (0x2 << 2) |
166 | #define DA7213_PLL_INDIV_40_54_MHZ (0x3 << 2) | 169 | #define DA7213_PLL_INDIV_36_TO_54_MHZ (0x3 << 2) |
167 | #define DA7213_PLL_INDIV_MASK (0x3 << 2) | 170 | #define DA7213_PLL_INDIV_MASK (0x3 << 2) |
168 | #define DA7213_PLL_MCLK_SQR_EN (0x1 << 4) | 171 | #define DA7213_PLL_MCLK_SQR_EN (0x1 << 4) |
169 | #define DA7213_PLL_32K_MODE (0x1 << 5) | 172 | #define DA7213_PLL_32K_MODE (0x1 << 5) |
@@ -178,8 +181,6 @@ | |||
178 | #define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) | 181 | #define DA7213_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) |
179 | #define DA7213_DAI_CLK_POL_INV (0x1 << 2) | 182 | #define DA7213_DAI_CLK_POL_INV (0x1 << 2) |
180 | #define DA7213_DAI_WCLK_POL_INV (0x1 << 3) | 183 | #define DA7213_DAI_WCLK_POL_INV (0x1 << 3) |
181 | #define DA7213_DAI_CLK_EN_SLAVE_MODE (0x0 << 7) | ||
182 | #define DA7213_DAI_CLK_EN_MASTER_MODE (0x1 << 7) | ||
183 | #define DA7213_DAI_CLK_EN_MASK (0x1 << 7) | 184 | #define DA7213_DAI_CLK_EN_MASK (0x1 << 7) |
184 | 185 | ||
185 | /* DA7213_DAI_CTRL = 0x29 */ | 186 | /* DA7213_DAI_CTRL = 0x29 */ |
@@ -412,6 +413,9 @@ | |||
412 | #define DA7213_DMIC_CLK_RATE_SHIFT 2 | 413 | #define DA7213_DMIC_CLK_RATE_SHIFT 2 |
413 | #define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2) | 414 | #define DA7213_DMIC_CLK_RATE_MASK (0x1 << 2) |
414 | 415 | ||
416 | /* DA7213_PC_COUNT = 0x94 */ | ||
417 | #define DA7213_PC_FREERUN_MASK (0x1 << 0) | ||
418 | |||
415 | /* DA7213_DIG_CTRL = 0x99 */ | 419 | /* DA7213_DIG_CTRL = 0x99 */ |
416 | #define DA7213_DAC_L_INV_SHIFT 3 | 420 | #define DA7213_DAC_L_INV_SHIFT 3 |
417 | #define DA7213_DAC_R_INV_SHIFT 7 | 421 | #define DA7213_DAC_R_INV_SHIFT 7 |
@@ -495,15 +499,16 @@ | |||
495 | #define DA7213_ALC_AVG_ITERATIONS 5 | 499 | #define DA7213_ALC_AVG_ITERATIONS 5 |
496 | 500 | ||
497 | /* PLL related */ | 501 | /* PLL related */ |
498 | #define DA7213_SYSCLK_MCLK 0 | 502 | #define DA7213_SYSCLK_MCLK 0 |
499 | #define DA7213_SYSCLK_PLL 1 | 503 | #define DA7213_SYSCLK_PLL 1 |
500 | #define DA7213_PLL_FREQ_OUT_90316800 90316800 | 504 | #define DA7213_PLL_FREQ_OUT_90316800 90316800 |
501 | #define DA7213_PLL_FREQ_OUT_98304000 98304000 | 505 | #define DA7213_PLL_FREQ_OUT_98304000 98304000 |
502 | #define DA7213_PLL_FREQ_OUT_94310400 94310400 | 506 | #define DA7213_PLL_FREQ_OUT_94310400 94310400 |
503 | #define DA7213_PLL_INDIV_5_10_MHZ_VAL 2 | 507 | #define DA7213_PLL_INDIV_5_TO_9_MHZ_VAL 2 |
504 | #define DA7213_PLL_INDIV_10_20_MHZ_VAL 4 | 508 | #define DA7213_PLL_INDIV_9_TO_18_MHZ_VAL 4 |
505 | #define DA7213_PLL_INDIV_20_40_MHZ_VAL 8 | 509 | #define DA7213_PLL_INDIV_18_TO_36_MHZ_VAL 8 |
506 | #define DA7213_PLL_INDIV_40_54_MHZ_VAL 16 | 510 | #define DA7213_PLL_INDIV_36_TO_54_MHZ_VAL 16 |
511 | #define DA7213_SRM_CHECK_RETRIES 8 | ||
507 | 512 | ||
508 | enum da7213_clk_src { | 513 | enum da7213_clk_src { |
509 | DA7213_CLKSRC_MCLK = 0, | 514 | DA7213_CLKSRC_MCLK = 0, |
diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 93575f251866..99ce23e113bf 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c | |||
@@ -1868,27 +1868,27 @@ static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | |||
1868 | 1868 | ||
1869 | /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ | 1869 | /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ |
1870 | if (da7218->mclk_rate == 32768) { | 1870 | if (da7218->mclk_rate == 32768) { |
1871 | indiv_bits = DA7218_PLL_INDIV_2_5_MHZ; | 1871 | indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ; |
1872 | indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; | 1872 | indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL; |
1873 | } else if (da7218->mclk_rate < 2000000) { | 1873 | } else if (da7218->mclk_rate < 2000000) { |
1874 | dev_err(codec->dev, "PLL input clock %d below valid range\n", | 1874 | dev_err(codec->dev, "PLL input clock %d below valid range\n", |
1875 | da7218->mclk_rate); | 1875 | da7218->mclk_rate); |
1876 | return -EINVAL; | 1876 | return -EINVAL; |
1877 | } else if (da7218->mclk_rate <= 5000000) { | 1877 | } else if (da7218->mclk_rate <= 4500000) { |
1878 | indiv_bits = DA7218_PLL_INDIV_2_5_MHZ; | 1878 | indiv_bits = DA7218_PLL_INDIV_2_TO_4_5_MHZ; |
1879 | indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; | 1879 | indiv = DA7218_PLL_INDIV_2_TO_4_5_MHZ_VAL; |
1880 | } else if (da7218->mclk_rate <= 10000000) { | 1880 | } else if (da7218->mclk_rate <= 9000000) { |
1881 | indiv_bits = DA7218_PLL_INDIV_5_10_MHZ; | 1881 | indiv_bits = DA7218_PLL_INDIV_4_5_TO_9_MHZ; |
1882 | indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; | 1882 | indiv = DA7218_PLL_INDIV_4_5_TO_9_MHZ_VAL; |
1883 | } else if (da7218->mclk_rate <= 20000000) { | 1883 | } else if (da7218->mclk_rate <= 18000000) { |
1884 | indiv_bits = DA7218_PLL_INDIV_10_20_MHZ; | 1884 | indiv_bits = DA7218_PLL_INDIV_9_TO_18_MHZ; |
1885 | indiv = DA7218_PLL_INDIV_10_20_MHZ_VAL; | 1885 | indiv = DA7218_PLL_INDIV_9_TO_18_MHZ_VAL; |
1886 | } else if (da7218->mclk_rate <= 40000000) { | 1886 | } else if (da7218->mclk_rate <= 36000000) { |
1887 | indiv_bits = DA7218_PLL_INDIV_20_40_MHZ; | 1887 | indiv_bits = DA7218_PLL_INDIV_18_TO_36_MHZ; |
1888 | indiv = DA7218_PLL_INDIV_20_40_MHZ_VAL; | 1888 | indiv = DA7218_PLL_INDIV_18_TO_36_MHZ_VAL; |
1889 | } else if (da7218->mclk_rate <= 54000000) { | 1889 | } else if (da7218->mclk_rate <= 54000000) { |
1890 | indiv_bits = DA7218_PLL_INDIV_40_54_MHZ; | 1890 | indiv_bits = DA7218_PLL_INDIV_36_TO_54_MHZ; |
1891 | indiv = DA7218_PLL_INDIV_40_54_MHZ_VAL; | 1891 | indiv = DA7218_PLL_INDIV_36_TO_54_MHZ_VAL; |
1892 | } else { | 1892 | } else { |
1893 | dev_err(codec->dev, "PLL input clock %d above valid range\n", | 1893 | dev_err(codec->dev, "PLL input clock %d above valid range\n", |
1894 | da7218->mclk_rate); | 1894 | da7218->mclk_rate); |
diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h index c2c59049a2ad..477cd37723cf 100644 --- a/sound/soc/codecs/da7218.h +++ b/sound/soc/codecs/da7218.h | |||
@@ -876,15 +876,11 @@ | |||
876 | /* DA7218_PLL_CTRL = 0x91 */ | 876 | /* DA7218_PLL_CTRL = 0x91 */ |
877 | #define DA7218_PLL_INDIV_SHIFT 0 | 877 | #define DA7218_PLL_INDIV_SHIFT 0 |
878 | #define DA7218_PLL_INDIV_MASK (0x7 << 0) | 878 | #define DA7218_PLL_INDIV_MASK (0x7 << 0) |
879 | #define DA7218_PLL_INDIV_2_5_MHZ (0x0 << 0) | 879 | #define DA7218_PLL_INDIV_2_TO_4_5_MHZ (0x0 << 0) |
880 | #define DA7218_PLL_INDIV_5_10_MHZ (0x1 << 0) | 880 | #define DA7218_PLL_INDIV_4_5_TO_9_MHZ (0x1 << 0) |
881 | #define DA7218_PLL_INDIV_10_20_MHZ (0x2 << 0) | 881 | #define DA7218_PLL_INDIV_9_TO_18_MHZ (0x2 << 0) |
882 | #define DA7218_PLL_INDIV_20_40_MHZ (0x3 << 0) | 882 | #define DA7218_PLL_INDIV_18_TO_36_MHZ (0x3 << 0) |
883 | #define DA7218_PLL_INDIV_40_54_MHZ (0x4 << 0) | 883 | #define DA7218_PLL_INDIV_36_TO_54_MHZ (0x4 << 0) |
884 | #define DA7218_PLL_INDIV_2_10_MHZ_VAL 2 | ||
885 | #define DA7218_PLL_INDIV_10_20_MHZ_VAL 4 | ||
886 | #define DA7218_PLL_INDIV_20_40_MHZ_VAL 8 | ||
887 | #define DA7218_PLL_INDIV_40_54_MHZ_VAL 16 | ||
888 | #define DA7218_PLL_MCLK_SQR_EN_SHIFT 4 | 884 | #define DA7218_PLL_MCLK_SQR_EN_SHIFT 4 |
889 | #define DA7218_PLL_MCLK_SQR_EN_MASK (0x1 << 4) | 885 | #define DA7218_PLL_MCLK_SQR_EN_MASK (0x1 << 4) |
890 | #define DA7218_PLL_MODE_SHIFT 6 | 886 | #define DA7218_PLL_MODE_SHIFT 6 |
@@ -1336,6 +1332,13 @@ | |||
1336 | #define DA7218_PLL_FREQ_OUT_90316 90316800 | 1332 | #define DA7218_PLL_FREQ_OUT_90316 90316800 |
1337 | #define DA7218_PLL_FREQ_OUT_98304 98304000 | 1333 | #define DA7218_PLL_FREQ_OUT_98304 98304000 |
1338 | 1334 | ||
1335 | /* PLL Frequency Dividers */ | ||
1336 | #define DA7218_PLL_INDIV_2_TO_4_5_MHZ_VAL 1 | ||
1337 | #define DA7218_PLL_INDIV_4_5_TO_9_MHZ_VAL 2 | ||
1338 | #define DA7218_PLL_INDIV_9_TO_18_MHZ_VAL 4 | ||
1339 | #define DA7218_PLL_INDIV_18_TO_36_MHZ_VAL 8 | ||
1340 | #define DA7218_PLL_INDIV_36_TO_54_MHZ_VAL 16 | ||
1341 | |||
1339 | /* ALC Calibration */ | 1342 | /* ALC Calibration */ |
1340 | #define DA7218_ALC_CALIB_DELAY_MIN 2500 | 1343 | #define DA7218_ALC_CALIB_DELAY_MIN 2500 |
1341 | #define DA7218_ALC_CALIB_DELAY_MAX 5000 | 1344 | #define DA7218_ALC_CALIB_DELAY_MAX 5000 |
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 81c0708b85c1..5c93899f1f0e 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * option) any later version. | 11 | * option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/acpi.h> | ||
14 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
15 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
16 | #include <linux/of_device.h> | 17 | #include <linux/of_device.h> |
@@ -1025,7 +1026,7 @@ static int da7219_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
1025 | if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) | 1026 | if ((da7219->clk_src == clk_id) && (da7219->mclk_rate == freq)) |
1026 | return 0; | 1027 | return 0; |
1027 | 1028 | ||
1028 | if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) { | 1029 | if ((freq < 2000000) || (freq > 54000000)) { |
1029 | dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", | 1030 | dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", |
1030 | freq); | 1031 | freq); |
1031 | return -EINVAL; | 1032 | return -EINVAL; |
@@ -1079,21 +1080,21 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | |||
1079 | dev_err(codec->dev, "PLL input clock %d below valid range\n", | 1080 | dev_err(codec->dev, "PLL input clock %d below valid range\n", |
1080 | da7219->mclk_rate); | 1081 | da7219->mclk_rate); |
1081 | return -EINVAL; | 1082 | return -EINVAL; |
1082 | } else if (da7219->mclk_rate <= 5000000) { | 1083 | } else if (da7219->mclk_rate <= 4500000) { |
1083 | indiv_bits = DA7219_PLL_INDIV_2_5_MHZ; | 1084 | indiv_bits = DA7219_PLL_INDIV_2_TO_4_5_MHZ; |
1084 | indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL; | 1085 | indiv = DA7219_PLL_INDIV_2_TO_4_5_MHZ_VAL; |
1085 | } else if (da7219->mclk_rate <= 10000000) { | 1086 | } else if (da7219->mclk_rate <= 9000000) { |
1086 | indiv_bits = DA7219_PLL_INDIV_5_10_MHZ; | 1087 | indiv_bits = DA7219_PLL_INDIV_4_5_TO_9_MHZ; |
1087 | indiv = DA7219_PLL_INDIV_5_10_MHZ_VAL; | 1088 | indiv = DA7219_PLL_INDIV_4_5_TO_9_MHZ_VAL; |
1088 | } else if (da7219->mclk_rate <= 20000000) { | 1089 | } else if (da7219->mclk_rate <= 18000000) { |
1089 | indiv_bits = DA7219_PLL_INDIV_10_20_MHZ; | 1090 | indiv_bits = DA7219_PLL_INDIV_9_TO_18_MHZ; |
1090 | indiv = DA7219_PLL_INDIV_10_20_MHZ_VAL; | 1091 | indiv = DA7219_PLL_INDIV_9_TO_18_MHZ_VAL; |
1091 | } else if (da7219->mclk_rate <= 40000000) { | 1092 | } else if (da7219->mclk_rate <= 36000000) { |
1092 | indiv_bits = DA7219_PLL_INDIV_20_40_MHZ; | 1093 | indiv_bits = DA7219_PLL_INDIV_18_TO_36_MHZ; |
1093 | indiv = DA7219_PLL_INDIV_20_40_MHZ_VAL; | 1094 | indiv = DA7219_PLL_INDIV_18_TO_36_MHZ_VAL; |
1094 | } else if (da7219->mclk_rate <= 54000000) { | 1095 | } else if (da7219->mclk_rate <= 54000000) { |
1095 | indiv_bits = DA7219_PLL_INDIV_40_54_MHZ; | 1096 | indiv_bits = DA7219_PLL_INDIV_36_TO_54_MHZ; |
1096 | indiv = DA7219_PLL_INDIV_40_54_MHZ_VAL; | 1097 | indiv = DA7219_PLL_INDIV_36_TO_54_MHZ_VAL; |
1097 | } else { | 1098 | } else { |
1098 | dev_err(codec->dev, "PLL input clock %d above valid range\n", | 1099 | dev_err(codec->dev, "PLL input clock %d above valid range\n", |
1099 | da7219->mclk_rate); | 1100 | da7219->mclk_rate); |
@@ -1426,6 +1427,12 @@ static const struct of_device_id da7219_of_match[] = { | |||
1426 | }; | 1427 | }; |
1427 | MODULE_DEVICE_TABLE(of, da7219_of_match); | 1428 | MODULE_DEVICE_TABLE(of, da7219_of_match); |
1428 | 1429 | ||
1430 | static const struct acpi_device_id da7219_acpi_match[] = { | ||
1431 | { .id = "DLGS7219", }, | ||
1432 | { } | ||
1433 | }; | ||
1434 | MODULE_DEVICE_TABLE(acpi, da7219_acpi_match); | ||
1435 | |||
1429 | static enum da7219_micbias_voltage | 1436 | static enum da7219_micbias_voltage |
1430 | da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) | 1437 | da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) |
1431 | { | 1438 | { |
@@ -1955,6 +1962,7 @@ static struct i2c_driver da7219_i2c_driver = { | |||
1955 | .driver = { | 1962 | .driver = { |
1956 | .name = "da7219", | 1963 | .name = "da7219", |
1957 | .of_match_table = of_match_ptr(da7219_of_match), | 1964 | .of_match_table = of_match_ptr(da7219_of_match), |
1965 | .acpi_match_table = ACPI_PTR(da7219_acpi_match), | ||
1958 | }, | 1966 | }, |
1959 | .probe = da7219_i2c_probe, | 1967 | .probe = da7219_i2c_probe, |
1960 | .remove = da7219_i2c_remove, | 1968 | .remove = da7219_i2c_remove, |
diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 5a787e738084..ff2a2f02ce40 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h | |||
@@ -194,11 +194,11 @@ | |||
194 | /* DA7219_PLL_CTRL = 0x20 */ | 194 | /* DA7219_PLL_CTRL = 0x20 */ |
195 | #define DA7219_PLL_INDIV_SHIFT 2 | 195 | #define DA7219_PLL_INDIV_SHIFT 2 |
196 | #define DA7219_PLL_INDIV_MASK (0x7 << 2) | 196 | #define DA7219_PLL_INDIV_MASK (0x7 << 2) |
197 | #define DA7219_PLL_INDIV_2_5_MHZ (0x0 << 2) | 197 | #define DA7219_PLL_INDIV_2_TO_4_5_MHZ (0x0 << 2) |
198 | #define DA7219_PLL_INDIV_5_10_MHZ (0x1 << 2) | 198 | #define DA7219_PLL_INDIV_4_5_TO_9_MHZ (0x1 << 2) |
199 | #define DA7219_PLL_INDIV_10_20_MHZ (0x2 << 2) | 199 | #define DA7219_PLL_INDIV_9_TO_18_MHZ (0x2 << 2) |
200 | #define DA7219_PLL_INDIV_20_40_MHZ (0x3 << 2) | 200 | #define DA7219_PLL_INDIV_18_TO_36_MHZ (0x3 << 2) |
201 | #define DA7219_PLL_INDIV_40_54_MHZ (0x4 << 2) | 201 | #define DA7219_PLL_INDIV_36_TO_54_MHZ (0x4 << 2) |
202 | #define DA7219_PLL_MCLK_SQR_EN_SHIFT 5 | 202 | #define DA7219_PLL_MCLK_SQR_EN_SHIFT 5 |
203 | #define DA7219_PLL_MCLK_SQR_EN_MASK (0x1 << 5) | 203 | #define DA7219_PLL_MCLK_SQR_EN_MASK (0x1 << 5) |
204 | #define DA7219_PLL_MODE_SHIFT 6 | 204 | #define DA7219_PLL_MODE_SHIFT 6 |
@@ -761,11 +761,11 @@ | |||
761 | #define DA7219_PLL_FREQ_OUT_98304 98304000 | 761 | #define DA7219_PLL_FREQ_OUT_98304 98304000 |
762 | 762 | ||
763 | /* PLL Frequency Dividers */ | 763 | /* PLL Frequency Dividers */ |
764 | #define DA7219_PLL_INDIV_2_5_MHZ_VAL 1 | 764 | #define DA7219_PLL_INDIV_2_TO_4_5_MHZ_VAL 1 |
765 | #define DA7219_PLL_INDIV_5_10_MHZ_VAL 2 | 765 | #define DA7219_PLL_INDIV_4_5_TO_9_MHZ_VAL 2 |
766 | #define DA7219_PLL_INDIV_10_20_MHZ_VAL 4 | 766 | #define DA7219_PLL_INDIV_9_TO_18_MHZ_VAL 4 |
767 | #define DA7219_PLL_INDIV_20_40_MHZ_VAL 8 | 767 | #define DA7219_PLL_INDIV_18_TO_36_MHZ_VAL 8 |
768 | #define DA7219_PLL_INDIV_40_54_MHZ_VAL 16 | 768 | #define DA7219_PLL_INDIV_36_TO_54_MHZ_VAL 16 |
769 | 769 | ||
770 | /* SRM */ | 770 | /* SRM */ |
771 | #define DA7219_SRM_CHECK_RETRIES 8 | 771 | #define DA7219_SRM_CHECK_RETRIES 8 |
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c index afa6c5db9dcc..2086d7107622 100644 --- a/sound/soc/codecs/es8328.c +++ b/sound/soc/codecs/es8328.c | |||
@@ -26,18 +26,30 @@ | |||
26 | #include <sound/tlv.h> | 26 | #include <sound/tlv.h> |
27 | #include "es8328.h" | 27 | #include "es8328.h" |
28 | 28 | ||
29 | #define ES8328_SYSCLK_RATE_1X 11289600 | 29 | static const unsigned int rates_12288[] = { |
30 | #define ES8328_SYSCLK_RATE_2X 22579200 | 30 | 8000, 12000, 16000, 24000, 32000, 48000, 96000, |
31 | }; | ||
31 | 32 | ||
32 | /* Run the codec at 22.5792 or 11.2896 MHz to support these rates */ | 33 | static const int ratios_12288[] = { |
33 | static struct { | 34 | 10, 7, 6, 4, 3, 2, 0, |
34 | int rate; | 35 | }; |
35 | u8 ratio; | 36 | |
36 | } mclk_ratios[] = { | 37 | static const struct snd_pcm_hw_constraint_list constraints_12288 = { |
37 | { 8000, 9 }, | 38 | .count = ARRAY_SIZE(rates_12288), |
38 | {11025, 7 }, | 39 | .list = rates_12288, |
39 | {22050, 4 }, | 40 | }; |
40 | {44100, 2 }, | 41 | |
42 | static const unsigned int rates_11289[] = { | ||
43 | 8018, 11025, 22050, 44100, 88200, | ||
44 | }; | ||
45 | |||
46 | static const int ratios_11289[] = { | ||
47 | 9, 7, 4, 2, 0, | ||
48 | }; | ||
49 | |||
50 | static const struct snd_pcm_hw_constraint_list constraints_11289 = { | ||
51 | .count = ARRAY_SIZE(rates_11289), | ||
52 | .list = rates_11289, | ||
41 | }; | 53 | }; |
42 | 54 | ||
43 | /* regulator supplies for sgtl5000, VDDD is an optional external supply */ | 55 | /* regulator supplies for sgtl5000, VDDD is an optional external supply */ |
@@ -57,16 +69,28 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = { | |||
57 | "HPVDD", | 69 | "HPVDD", |
58 | }; | 70 | }; |
59 | 71 | ||
60 | #define ES8328_RATES (SNDRV_PCM_RATE_44100 | \ | 72 | #define ES8328_RATES (SNDRV_PCM_RATE_96000 | \ |
73 | SNDRV_PCM_RATE_48000 | \ | ||
74 | SNDRV_PCM_RATE_44100 | \ | ||
75 | SNDRV_PCM_RATE_32000 | \ | ||
61 | SNDRV_PCM_RATE_22050 | \ | 76 | SNDRV_PCM_RATE_22050 | \ |
62 | SNDRV_PCM_RATE_11025) | 77 | SNDRV_PCM_RATE_16000 | \ |
63 | #define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) | 78 | SNDRV_PCM_RATE_11025 | \ |
79 | SNDRV_PCM_RATE_8000) | ||
80 | #define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
81 | SNDRV_PCM_FMTBIT_S18_3LE | \ | ||
82 | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
83 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
84 | SNDRV_PCM_FMTBIT_S32_LE) | ||
64 | 85 | ||
65 | struct es8328_priv { | 86 | struct es8328_priv { |
66 | struct regmap *regmap; | 87 | struct regmap *regmap; |
67 | struct clk *clk; | 88 | struct clk *clk; |
68 | int playback_fs; | 89 | int playback_fs; |
69 | bool deemph; | 90 | bool deemph; |
91 | int mclkdiv2; | ||
92 | const struct snd_pcm_hw_constraint_list *sysclk_constraints; | ||
93 | const int *mclk_ratios; | ||
70 | struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; | 94 | struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; |
71 | }; | 95 | }; |
72 | 96 | ||
@@ -439,54 +463,131 @@ static int es8328_mute(struct snd_soc_dai *dai, int mute) | |||
439 | mute ? ES8328_DACCONTROL3_DACMUTE : 0); | 463 | mute ? ES8328_DACCONTROL3_DACMUTE : 0); |
440 | } | 464 | } |
441 | 465 | ||
466 | static int es8328_startup(struct snd_pcm_substream *substream, | ||
467 | struct snd_soc_dai *dai) | ||
468 | { | ||
469 | struct snd_soc_codec *codec = dai->codec; | ||
470 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
471 | |||
472 | if (es8328->sysclk_constraints) | ||
473 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
474 | SNDRV_PCM_HW_PARAM_RATE, | ||
475 | es8328->sysclk_constraints); | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | |||
442 | static int es8328_hw_params(struct snd_pcm_substream *substream, | 480 | static int es8328_hw_params(struct snd_pcm_substream *substream, |
443 | struct snd_pcm_hw_params *params, | 481 | struct snd_pcm_hw_params *params, |
444 | struct snd_soc_dai *dai) | 482 | struct snd_soc_dai *dai) |
445 | { | 483 | { |
446 | struct snd_soc_codec *codec = dai->codec; | 484 | struct snd_soc_codec *codec = dai->codec; |
447 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | 485 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); |
448 | int clk_rate; | ||
449 | int i; | 486 | int i; |
450 | int reg; | 487 | int reg; |
451 | u8 ratio; | 488 | int wl; |
489 | int ratio; | ||
490 | |||
491 | if (!es8328->sysclk_constraints) { | ||
492 | dev_err(codec->dev, "No MCLK configured\n"); | ||
493 | return -EINVAL; | ||
494 | } | ||
452 | 495 | ||
453 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 496 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
454 | reg = ES8328_DACCONTROL2; | 497 | reg = ES8328_DACCONTROL2; |
455 | else | 498 | else |
456 | reg = ES8328_ADCCONTROL5; | 499 | reg = ES8328_ADCCONTROL5; |
457 | 500 | ||
458 | clk_rate = clk_get_rate(es8328->clk); | 501 | for (i = 0; i < es8328->sysclk_constraints->count; i++) |
502 | if (es8328->sysclk_constraints->list[i] == params_rate(params)) | ||
503 | break; | ||
459 | 504 | ||
460 | if ((clk_rate != ES8328_SYSCLK_RATE_1X) && | 505 | if (i == es8328->sysclk_constraints->count) { |
461 | (clk_rate != ES8328_SYSCLK_RATE_2X)) { | 506 | dev_err(codec->dev, "LRCLK %d unsupported with current clock\n", |
462 | dev_err(codec->dev, | 507 | params_rate(params)); |
463 | "%s: clock is running at %d Hz, not %d or %d Hz\n", | ||
464 | __func__, clk_rate, | ||
465 | ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X); | ||
466 | return -EINVAL; | 508 | return -EINVAL; |
467 | } | 509 | } |
468 | 510 | ||
469 | /* find master mode MCLK to sampling frequency ratio */ | 511 | ratio = es8328->mclk_ratios[i]; |
470 | ratio = mclk_ratios[0].rate; | 512 | snd_soc_update_bits(codec, ES8328_MASTERMODE, |
471 | for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++) | 513 | ES8328_MASTERMODE_MCLKDIV2, |
472 | if (params_rate(params) <= mclk_ratios[i].rate) | 514 | es8328->mclkdiv2 ? ES8328_MASTERMODE_MCLKDIV2 : 0); |
473 | ratio = mclk_ratios[i].ratio; | 515 | |
516 | switch (params_width(params)) { | ||
517 | case 16: | ||
518 | wl = 3; | ||
519 | break; | ||
520 | case 18: | ||
521 | wl = 2; | ||
522 | break; | ||
523 | case 20: | ||
524 | wl = 1; | ||
525 | break; | ||
526 | case 24: | ||
527 | wl = 0; | ||
528 | break; | ||
529 | case 32: | ||
530 | wl = 4; | ||
531 | break; | ||
532 | default: | ||
533 | return -EINVAL; | ||
534 | } | ||
474 | 535 | ||
475 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 536 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
537 | snd_soc_update_bits(codec, ES8328_DACCONTROL1, | ||
538 | ES8328_DACCONTROL1_DACWL_MASK, | ||
539 | wl << ES8328_DACCONTROL1_DACWL_SHIFT); | ||
540 | |||
476 | es8328->playback_fs = params_rate(params); | 541 | es8328->playback_fs = params_rate(params); |
477 | es8328_set_deemph(codec); | 542 | es8328_set_deemph(codec); |
478 | } | 543 | } else |
544 | snd_soc_update_bits(codec, ES8328_ADCCONTROL4, | ||
545 | ES8328_ADCCONTROL4_ADCWL_MASK, | ||
546 | wl << ES8328_ADCCONTROL4_ADCWL_SHIFT); | ||
479 | 547 | ||
480 | return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); | 548 | return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); |
481 | } | 549 | } |
482 | 550 | ||
551 | static int es8328_set_sysclk(struct snd_soc_dai *codec_dai, | ||
552 | int clk_id, unsigned int freq, int dir) | ||
553 | { | ||
554 | struct snd_soc_codec *codec = codec_dai->codec; | ||
555 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
556 | int mclkdiv2 = 0; | ||
557 | |||
558 | switch (freq) { | ||
559 | case 0: | ||
560 | es8328->sysclk_constraints = NULL; | ||
561 | es8328->mclk_ratios = NULL; | ||
562 | break; | ||
563 | case 22579200: | ||
564 | mclkdiv2 = 1; | ||
565 | /* fallthru */ | ||
566 | case 11289600: | ||
567 | es8328->sysclk_constraints = &constraints_11289; | ||
568 | es8328->mclk_ratios = ratios_11289; | ||
569 | break; | ||
570 | case 24576000: | ||
571 | mclkdiv2 = 1; | ||
572 | /* fallthru */ | ||
573 | case 12288000: | ||
574 | es8328->sysclk_constraints = &constraints_12288; | ||
575 | es8328->mclk_ratios = ratios_12288; | ||
576 | break; | ||
577 | default: | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | es8328->mclkdiv2 = mclkdiv2; | ||
582 | return 0; | ||
583 | } | ||
584 | |||
483 | static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, | 585 | static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, |
484 | unsigned int fmt) | 586 | unsigned int fmt) |
485 | { | 587 | { |
486 | struct snd_soc_codec *codec = codec_dai->codec; | 588 | struct snd_soc_codec *codec = codec_dai->codec; |
487 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | 589 | u8 dac_mode = 0; |
488 | int clk_rate; | 590 | u8 adc_mode = 0; |
489 | u8 mode = ES8328_DACCONTROL1_DACWL_16; | ||
490 | 591 | ||
491 | /* set master/slave audio interface */ | 592 | /* set master/slave audio interface */ |
492 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) | 593 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) |
@@ -495,13 +596,16 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
495 | /* interface format */ | 596 | /* interface format */ |
496 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 597 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
497 | case SND_SOC_DAIFMT_I2S: | 598 | case SND_SOC_DAIFMT_I2S: |
498 | mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; | 599 | dac_mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; |
600 | adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_I2S; | ||
499 | break; | 601 | break; |
500 | case SND_SOC_DAIFMT_RIGHT_J: | 602 | case SND_SOC_DAIFMT_RIGHT_J: |
501 | mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; | 603 | dac_mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; |
604 | adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_RJUST; | ||
502 | break; | 605 | break; |
503 | case SND_SOC_DAIFMT_LEFT_J: | 606 | case SND_SOC_DAIFMT_LEFT_J: |
504 | mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; | 607 | dac_mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; |
608 | adc_mode |= ES8328_ADCCONTROL4_ADCFORMAT_LJUST; | ||
505 | break; | 609 | break; |
506 | default: | 610 | default: |
507 | return -EINVAL; | 611 | return -EINVAL; |
@@ -511,18 +615,14 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
511 | if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) | 615 | if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) |
512 | return -EINVAL; | 616 | return -EINVAL; |
513 | 617 | ||
514 | snd_soc_write(codec, ES8328_DACCONTROL1, mode); | 618 | snd_soc_update_bits(codec, ES8328_DACCONTROL1, |
515 | snd_soc_write(codec, ES8328_ADCCONTROL4, mode); | 619 | ES8328_DACCONTROL1_DACFORMAT_MASK, dac_mode); |
620 | snd_soc_update_bits(codec, ES8328_ADCCONTROL4, | ||
621 | ES8328_ADCCONTROL4_ADCFORMAT_MASK, adc_mode); | ||
516 | 622 | ||
517 | /* Master serial port mode, with BCLK generated automatically */ | 623 | /* Master serial port mode, with BCLK generated automatically */ |
518 | clk_rate = clk_get_rate(es8328->clk); | 624 | snd_soc_update_bits(codec, ES8328_MASTERMODE, |
519 | if (clk_rate == ES8328_SYSCLK_RATE_1X) | 625 | ES8328_MASTERMODE_MSC, ES8328_MASTERMODE_MSC); |
520 | snd_soc_write(codec, ES8328_MASTERMODE, | ||
521 | ES8328_MASTERMODE_MSC); | ||
522 | else | ||
523 | snd_soc_write(codec, ES8328_MASTERMODE, | ||
524 | ES8328_MASTERMODE_MCLKDIV2 | | ||
525 | ES8328_MASTERMODE_MSC); | ||
526 | 626 | ||
527 | return 0; | 627 | return 0; |
528 | } | 628 | } |
@@ -579,8 +679,10 @@ static int es8328_set_bias_level(struct snd_soc_codec *codec, | |||
579 | } | 679 | } |
580 | 680 | ||
581 | static const struct snd_soc_dai_ops es8328_dai_ops = { | 681 | static const struct snd_soc_dai_ops es8328_dai_ops = { |
682 | .startup = es8328_startup, | ||
582 | .hw_params = es8328_hw_params, | 683 | .hw_params = es8328_hw_params, |
583 | .digital_mute = es8328_mute, | 684 | .digital_mute = es8328_mute, |
685 | .set_sysclk = es8328_set_sysclk, | ||
584 | .set_fmt = es8328_set_dai_fmt, | 686 | .set_fmt = es8328_set_dai_fmt, |
585 | }; | 687 | }; |
586 | 688 | ||
@@ -601,6 +703,7 @@ static struct snd_soc_dai_driver es8328_dai = { | |||
601 | .formats = ES8328_FORMATS, | 703 | .formats = ES8328_FORMATS, |
602 | }, | 704 | }, |
603 | .ops = &es8328_dai_ops, | 705 | .ops = &es8328_dai_ops, |
706 | .symmetric_rates = 1, | ||
604 | }; | 707 | }; |
605 | 708 | ||
606 | static int es8328_suspend(struct snd_soc_codec *codec) | 709 | static int es8328_suspend(struct snd_soc_codec *codec) |
@@ -708,6 +811,7 @@ const struct regmap_config es8328_regmap_config = { | |||
708 | .val_bits = 8, | 811 | .val_bits = 8, |
709 | .max_register = ES8328_REG_MAX, | 812 | .max_register = ES8328_REG_MAX, |
710 | .cache_type = REGCACHE_RBTREE, | 813 | .cache_type = REGCACHE_RBTREE, |
814 | .use_single_rw = true, | ||
711 | }; | 815 | }; |
712 | EXPORT_SYMBOL_GPL(es8328_regmap_config); | 816 | EXPORT_SYMBOL_GPL(es8328_regmap_config); |
713 | 817 | ||
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h index 156c748c89c7..1a736e72a929 100644 --- a/sound/soc/codecs/es8328.h +++ b/sound/soc/codecs/es8328.h | |||
@@ -22,7 +22,7 @@ int es8328_probe(struct device *dev, struct regmap *regmap); | |||
22 | #define ES8328_CONTROL1_VMIDSEL_50k (1 << 0) | 22 | #define ES8328_CONTROL1_VMIDSEL_50k (1 << 0) |
23 | #define ES8328_CONTROL1_VMIDSEL_500k (2 << 0) | 23 | #define ES8328_CONTROL1_VMIDSEL_500k (2 << 0) |
24 | #define ES8328_CONTROL1_VMIDSEL_5k (3 << 0) | 24 | #define ES8328_CONTROL1_VMIDSEL_5k (3 << 0) |
25 | #define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0) | 25 | #define ES8328_CONTROL1_VMIDSEL_MASK (3 << 0) |
26 | #define ES8328_CONTROL1_ENREF (1 << 2) | 26 | #define ES8328_CONTROL1_ENREF (1 << 2) |
27 | #define ES8328_CONTROL1_SEQEN (1 << 3) | 27 | #define ES8328_CONTROL1_SEQEN (1 << 3) |
28 | #define ES8328_CONTROL1_SAMEFS (1 << 4) | 28 | #define ES8328_CONTROL1_SAMEFS (1 << 4) |
@@ -84,7 +84,20 @@ int es8328_probe(struct device *dev, struct regmap *regmap); | |||
84 | #define ES8328_ADCCONTROL1 0x09 | 84 | #define ES8328_ADCCONTROL1 0x09 |
85 | #define ES8328_ADCCONTROL2 0x0a | 85 | #define ES8328_ADCCONTROL2 0x0a |
86 | #define ES8328_ADCCONTROL3 0x0b | 86 | #define ES8328_ADCCONTROL3 0x0b |
87 | |||
87 | #define ES8328_ADCCONTROL4 0x0c | 88 | #define ES8328_ADCCONTROL4 0x0c |
89 | #define ES8328_ADCCONTROL4_ADCFORMAT_MASK (3 << 0) | ||
90 | #define ES8328_ADCCONTROL4_ADCFORMAT_I2S (0 << 0) | ||
91 | #define ES8328_ADCCONTROL4_ADCFORMAT_LJUST (1 << 0) | ||
92 | #define ES8328_ADCCONTROL4_ADCFORMAT_RJUST (2 << 0) | ||
93 | #define ES8328_ADCCONTROL4_ADCFORMAT_PCM (3 << 0) | ||
94 | #define ES8328_ADCCONTROL4_ADCWL_SHIFT 2 | ||
95 | #define ES8328_ADCCONTROL4_ADCWL_MASK (7 << 2) | ||
96 | #define ES8328_ADCCONTROL4_ADCLRP_I2S_POL_NORMAL (0 << 5) | ||
97 | #define ES8328_ADCCONTROL4_ADCLRP_I2S_POL_INV (1 << 5) | ||
98 | #define ES8328_ADCCONTROL4_ADCLRP_PCM_MSB_CLK2 (0 << 5) | ||
99 | #define ES8328_ADCCONTROL4_ADCLRP_PCM_MSB_CLK1 (1 << 5) | ||
100 | |||
88 | #define ES8328_ADCCONTROL5 0x0d | 101 | #define ES8328_ADCCONTROL5 0x0d |
89 | #define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0) | 102 | #define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0) |
90 | 103 | ||
@@ -109,15 +122,13 @@ int es8328_probe(struct device *dev, struct regmap *regmap); | |||
109 | #define ES8328_ADCCONTROL14 0x16 | 122 | #define ES8328_ADCCONTROL14 0x16 |
110 | 123 | ||
111 | #define ES8328_DACCONTROL1 0x17 | 124 | #define ES8328_DACCONTROL1 0x17 |
125 | #define ES8328_DACCONTROL1_DACFORMAT_MASK (3 << 1) | ||
112 | #define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1) | 126 | #define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1) |
113 | #define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1) | 127 | #define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1) |
114 | #define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1) | 128 | #define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1) |
115 | #define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1) | 129 | #define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1) |
116 | #define ES8328_DACCONTROL1_DACWL_24 (0 << 3) | 130 | #define ES8328_DACCONTROL1_DACWL_SHIFT 3 |
117 | #define ES8328_DACCONTROL1_DACWL_20 (1 << 3) | 131 | #define ES8328_DACCONTROL1_DACWL_MASK (7 << 3) |
118 | #define ES8328_DACCONTROL1_DACWL_18 (2 << 3) | ||
119 | #define ES8328_DACCONTROL1_DACWL_16 (3 << 3) | ||
120 | #define ES8328_DACCONTROL1_DACWL_32 (4 << 3) | ||
121 | #define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6) | 132 | #define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6) |
122 | #define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6) | 133 | #define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6) |
123 | #define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6) | 134 | #define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6) |
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 26f9459cb3bc..181cd3bf0b92 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <sound/hdaudio_ext.h> | 29 | #include <sound/hdaudio_ext.h> |
30 | #include <sound/hda_i915.h> | 30 | #include <sound/hda_i915.h> |
31 | #include <sound/pcm_drm_eld.h> | 31 | #include <sound/pcm_drm_eld.h> |
32 | #include <sound/hda_chmap.h> | ||
32 | #include "../../hda/local.h" | 33 | #include "../../hda/local.h" |
33 | #include "hdac_hdmi.h" | 34 | #include "hdac_hdmi.h" |
34 | 35 | ||
@@ -60,11 +61,17 @@ struct hdac_hdmi_cvt { | |||
60 | struct hdac_hdmi_cvt_params params; | 61 | struct hdac_hdmi_cvt_params params; |
61 | }; | 62 | }; |
62 | 63 | ||
64 | /* Currently only spk_alloc, more to be added */ | ||
65 | struct hdac_hdmi_parsed_eld { | ||
66 | u8 spk_alloc; | ||
67 | }; | ||
68 | |||
63 | struct hdac_hdmi_eld { | 69 | struct hdac_hdmi_eld { |
64 | bool monitor_present; | 70 | bool monitor_present; |
65 | bool eld_valid; | 71 | bool eld_valid; |
66 | int eld_size; | 72 | int eld_size; |
67 | char eld_buffer[ELD_MAX_SIZE]; | 73 | char eld_buffer[ELD_MAX_SIZE]; |
74 | struct hdac_hdmi_parsed_eld info; | ||
68 | }; | 75 | }; |
69 | 76 | ||
70 | struct hdac_hdmi_pin { | 77 | struct hdac_hdmi_pin { |
@@ -76,6 +83,10 @@ struct hdac_hdmi_pin { | |||
76 | struct hdac_ext_device *edev; | 83 | struct hdac_ext_device *edev; |
77 | int repoll_count; | 84 | int repoll_count; |
78 | struct delayed_work work; | 85 | struct delayed_work work; |
86 | struct mutex lock; | ||
87 | bool chmap_set; | ||
88 | unsigned char chmap[8]; /* ALSA API channel-map */ | ||
89 | int channels; /* current number of channels */ | ||
79 | }; | 90 | }; |
80 | 91 | ||
81 | struct hdac_hdmi_pcm { | 92 | struct hdac_hdmi_pcm { |
@@ -100,8 +111,22 @@ struct hdac_hdmi_priv { | |||
100 | int num_pin; | 111 | int num_pin; |
101 | int num_cvt; | 112 | int num_cvt; |
102 | struct mutex pin_mutex; | 113 | struct mutex pin_mutex; |
114 | struct hdac_chmap chmap; | ||
103 | }; | 115 | }; |
104 | 116 | ||
117 | static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi, | ||
118 | int pcm_idx) | ||
119 | { | ||
120 | struct hdac_hdmi_pcm *pcm; | ||
121 | |||
122 | list_for_each_entry(pcm, &hdmi->pcm_list, head) { | ||
123 | if (pcm->pcm_id == pcm_idx) | ||
124 | return pcm; | ||
125 | } | ||
126 | |||
127 | return NULL; | ||
128 | } | ||
129 | |||
105 | static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) | 130 | static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) |
106 | { | 131 | { |
107 | struct hdac_device *hdac = dev_to_hdac_dev(dev); | 132 | struct hdac_device *hdac = dev_to_hdac_dev(dev); |
@@ -278,26 +303,31 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, | |||
278 | int i; | 303 | int i; |
279 | const u8 *eld_buf; | 304 | const u8 *eld_buf; |
280 | u8 conn_type; | 305 | u8 conn_type; |
281 | int channels = 2; | 306 | int channels, ca; |
282 | 307 | ||
283 | list_for_each_entry(pin, &hdmi->pin_list, head) { | 308 | list_for_each_entry(pin, &hdmi->pin_list, head) { |
284 | if (pin->nid == pin_nid) | 309 | if (pin->nid == pin_nid) |
285 | break; | 310 | break; |
286 | } | 311 | } |
287 | 312 | ||
313 | ca = snd_hdac_channel_allocation(&hdac->hdac, pin->eld.info.spk_alloc, | ||
314 | pin->channels, pin->chmap_set, true, pin->chmap); | ||
315 | |||
316 | channels = snd_hdac_get_active_channels(ca); | ||
317 | hdmi->chmap.ops.set_channel_count(&hdac->hdac, cvt_nid, channels); | ||
318 | |||
319 | snd_hdac_setup_channel_mapping(&hdmi->chmap, pin->nid, false, ca, | ||
320 | pin->channels, pin->chmap, pin->chmap_set); | ||
321 | |||
288 | eld_buf = pin->eld.eld_buffer; | 322 | eld_buf = pin->eld.eld_buffer; |
289 | conn_type = drm_eld_get_conn_type(eld_buf); | 323 | conn_type = drm_eld_get_conn_type(eld_buf); |
290 | 324 | ||
291 | /* setup channel count */ | ||
292 | snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, | ||
293 | AC_VERB_SET_CVT_CHAN_COUNT, channels - 1); | ||
294 | |||
295 | switch (conn_type) { | 325 | switch (conn_type) { |
296 | case DRM_ELD_CONN_TYPE_HDMI: | 326 | case DRM_ELD_CONN_TYPE_HDMI: |
297 | hdmi_audio_infoframe_init(&frame); | 327 | hdmi_audio_infoframe_init(&frame); |
298 | 328 | ||
299 | /* Default stereo for now */ | ||
300 | frame.channels = channels; | 329 | frame.channels = channels; |
330 | frame.channel_allocation = ca; | ||
301 | 331 | ||
302 | ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); | 332 | ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); |
303 | if (ret < 0) | 333 | if (ret < 0) |
@@ -311,7 +341,7 @@ static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, | |||
311 | dp_ai.len = 0x1b; | 341 | dp_ai.len = 0x1b; |
312 | dp_ai.ver = 0x11 << 2; | 342 | dp_ai.ver = 0x11 << 2; |
313 | dp_ai.CC02_CT47 = channels - 1; | 343 | dp_ai.CC02_CT47 = channels - 1; |
314 | dp_ai.CA = 0; | 344 | dp_ai.CA = ca; |
315 | 345 | ||
316 | dip = (u8 *)&dp_ai; | 346 | dip = (u8 *)&dp_ai; |
317 | break; | 347 | break; |
@@ -370,17 +400,23 @@ static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, | |||
370 | struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); | 400 | struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); |
371 | struct hdac_hdmi_priv *hdmi = hdac->private_data; | 401 | struct hdac_hdmi_priv *hdmi = hdac->private_data; |
372 | struct hdac_hdmi_dai_pin_map *dai_map; | 402 | struct hdac_hdmi_dai_pin_map *dai_map; |
403 | struct hdac_hdmi_pin *pin; | ||
373 | struct hdac_ext_dma_params *dd; | 404 | struct hdac_ext_dma_params *dd; |
374 | int ret; | 405 | int ret; |
375 | 406 | ||
376 | dai_map = &hdmi->dai_map[dai->id]; | 407 | dai_map = &hdmi->dai_map[dai->id]; |
408 | pin = dai_map->pin; | ||
377 | 409 | ||
378 | dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); | 410 | dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); |
379 | dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", | 411 | dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", |
380 | dd->stream_tag, dd->format); | 412 | dd->stream_tag, dd->format); |
381 | 413 | ||
414 | mutex_lock(&pin->lock); | ||
415 | pin->channels = substream->runtime->channels; | ||
416 | |||
382 | ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, | 417 | ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, |
383 | dai_map->pin->nid); | 418 | dai_map->pin->nid); |
419 | mutex_unlock(&pin->lock); | ||
384 | if (ret < 0) | 420 | if (ret < 0) |
385 | return ret; | 421 | return ret; |
386 | 422 | ||
@@ -640,6 +676,12 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, | |||
640 | snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, | 676 | snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, |
641 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); | 677 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); |
642 | 678 | ||
679 | mutex_lock(&dai_map->pin->lock); | ||
680 | dai_map->pin->chmap_set = false; | ||
681 | memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap)); | ||
682 | dai_map->pin->channels = 0; | ||
683 | mutex_unlock(&dai_map->pin->lock); | ||
684 | |||
643 | dai_map->pin = NULL; | 685 | dai_map->pin = NULL; |
644 | } | 686 | } |
645 | } | 687 | } |
@@ -647,10 +689,19 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, | |||
647 | static int | 689 | static int |
648 | hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) | 690 | hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) |
649 | { | 691 | { |
692 | unsigned int chans; | ||
693 | struct hdac_ext_device *edev = to_ehdac_device(hdac); | ||
694 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
650 | int err; | 695 | int err; |
651 | 696 | ||
652 | /* Only stereo supported as of now */ | 697 | chans = get_wcaps(hdac, cvt->nid); |
653 | cvt->params.channels_min = cvt->params.channels_max = 2; | 698 | chans = get_wcaps_channels(chans); |
699 | |||
700 | cvt->params.channels_min = 2; | ||
701 | |||
702 | cvt->params.channels_max = chans; | ||
703 | if (chans > hdmi->chmap.channels_max) | ||
704 | hdmi->chmap.channels_max = chans; | ||
654 | 705 | ||
655 | err = snd_hdac_query_supported_pcm(hdac, cvt->nid, | 706 | err = snd_hdac_query_supported_pcm(hdac, cvt->nid, |
656 | &cvt->params.rates, | 707 | &cvt->params.rates, |
@@ -1008,6 +1059,12 @@ static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) | |||
1008 | return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); | 1059 | return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); |
1009 | } | 1060 | } |
1010 | 1061 | ||
1062 | static void hdac_hdmi_parse_eld(struct hdac_ext_device *edev, | ||
1063 | struct hdac_hdmi_pin *pin) | ||
1064 | { | ||
1065 | pin->eld.info.spk_alloc = pin->eld.eld_buffer[DRM_ELD_SPEAKER]; | ||
1066 | } | ||
1067 | |||
1011 | static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) | 1068 | static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) |
1012 | { | 1069 | { |
1013 | struct hdac_ext_device *edev = pin->edev; | 1070 | struct hdac_ext_device *edev = pin->edev; |
@@ -1065,6 +1122,7 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) | |||
1065 | 1122 | ||
1066 | snd_jack_report(pcm->jack, SND_JACK_AVOUT); | 1123 | snd_jack_report(pcm->jack, SND_JACK_AVOUT); |
1067 | } | 1124 | } |
1125 | hdac_hdmi_parse_eld(edev, pin); | ||
1068 | 1126 | ||
1069 | print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, | 1127 | print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, |
1070 | pin->eld.eld_buffer, pin->eld.eld_size); | 1128 | pin->eld.eld_buffer, pin->eld.eld_size); |
@@ -1123,6 +1181,7 @@ static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) | |||
1123 | hdmi->num_pin++; | 1181 | hdmi->num_pin++; |
1124 | 1182 | ||
1125 | pin->edev = edev; | 1183 | pin->edev = edev; |
1184 | mutex_init(&pin->lock); | ||
1126 | INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); | 1185 | INIT_DELAYED_WORK(&pin->work, hdac_hdmi_repoll_eld); |
1127 | 1186 | ||
1128 | return 0; | 1187 | return 0; |
@@ -1342,6 +1401,19 @@ static struct i915_audio_component_audio_ops aops = { | |||
1342 | .pin_eld_notify = hdac_hdmi_eld_notify_cb, | 1401 | .pin_eld_notify = hdac_hdmi_eld_notify_cb, |
1343 | }; | 1402 | }; |
1344 | 1403 | ||
1404 | static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card, | ||
1405 | int device) | ||
1406 | { | ||
1407 | struct snd_soc_pcm_runtime *rtd; | ||
1408 | |||
1409 | list_for_each_entry(rtd, &card->rtd_list, list) { | ||
1410 | if (rtd->pcm && (rtd->pcm->device == device)) | ||
1411 | return rtd->pcm; | ||
1412 | } | ||
1413 | |||
1414 | return NULL; | ||
1415 | } | ||
1416 | |||
1345 | int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) | 1417 | int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) |
1346 | { | 1418 | { |
1347 | char jack_name[NAME_SIZE]; | 1419 | char jack_name[NAME_SIZE]; |
@@ -1351,6 +1423,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) | |||
1351 | snd_soc_component_get_dapm(&codec->component); | 1423 | snd_soc_component_get_dapm(&codec->component); |
1352 | struct hdac_hdmi_priv *hdmi = edev->private_data; | 1424 | struct hdac_hdmi_priv *hdmi = edev->private_data; |
1353 | struct hdac_hdmi_pcm *pcm; | 1425 | struct hdac_hdmi_pcm *pcm; |
1426 | struct snd_pcm *snd_pcm; | ||
1427 | int err; | ||
1354 | 1428 | ||
1355 | /* | 1429 | /* |
1356 | * this is a new PCM device, create new pcm and | 1430 | * this is a new PCM device, create new pcm and |
@@ -1362,6 +1436,18 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device) | |||
1362 | pcm->pcm_id = device; | 1436 | pcm->pcm_id = device; |
1363 | pcm->cvt = hdmi->dai_map[dai->id].cvt; | 1437 | pcm->cvt = hdmi->dai_map[dai->id].cvt; |
1364 | 1438 | ||
1439 | snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device); | ||
1440 | if (snd_pcm) { | ||
1441 | err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap); | ||
1442 | if (err < 0) { | ||
1443 | dev_err(&edev->hdac.dev, | ||
1444 | "chmap control add failed with err: %d for pcm: %d\n", | ||
1445 | err, device); | ||
1446 | kfree(pcm); | ||
1447 | return err; | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1365 | list_add_tail(&pcm->head, &hdmi->pcm_list); | 1451 | list_add_tail(&pcm->head, &hdmi->pcm_list); |
1366 | 1452 | ||
1367 | sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); | 1453 | sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device); |
@@ -1378,10 +1464,18 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) | |||
1378 | struct snd_soc_dapm_context *dapm = | 1464 | struct snd_soc_dapm_context *dapm = |
1379 | snd_soc_component_get_dapm(&codec->component); | 1465 | snd_soc_component_get_dapm(&codec->component); |
1380 | struct hdac_hdmi_pin *pin; | 1466 | struct hdac_hdmi_pin *pin; |
1467 | struct hdac_ext_link *hlink = NULL; | ||
1381 | int ret; | 1468 | int ret; |
1382 | 1469 | ||
1383 | edev->scodec = codec; | 1470 | edev->scodec = codec; |
1384 | 1471 | ||
1472 | /* | ||
1473 | * hold the ref while we probe, also no need to drop the ref on | ||
1474 | * exit, we call pm_runtime_suspend() so that will do for us | ||
1475 | */ | ||
1476 | hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); | ||
1477 | snd_hdac_ext_bus_link_get(edev->ebus, hlink); | ||
1478 | |||
1385 | ret = create_fill_widget_route_map(dapm); | 1479 | ret = create_fill_widget_route_map(dapm); |
1386 | if (ret < 0) | 1480 | if (ret < 0) |
1387 | return ret; | 1481 | return ret; |
@@ -1420,32 +1514,39 @@ static int hdmi_codec_remove(struct snd_soc_codec *codec) | |||
1420 | } | 1514 | } |
1421 | 1515 | ||
1422 | #ifdef CONFIG_PM | 1516 | #ifdef CONFIG_PM |
1423 | static int hdmi_codec_resume(struct snd_soc_codec *codec) | 1517 | static int hdmi_codec_prepare(struct device *dev) |
1424 | { | 1518 | { |
1425 | struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); | 1519 | struct hdac_ext_device *edev = to_hda_ext_device(dev); |
1520 | struct hdac_device *hdac = &edev->hdac; | ||
1521 | |||
1522 | pm_runtime_get_sync(&edev->hdac.dev); | ||
1523 | |||
1524 | /* | ||
1525 | * Power down afg. | ||
1526 | * codec_read is preferred over codec_write to set the power state. | ||
1527 | * This way verb is send to set the power state and response | ||
1528 | * is received. So setting power state is ensured without using loop | ||
1529 | * to read the state. | ||
1530 | */ | ||
1531 | snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, | ||
1532 | AC_PWRST_D3); | ||
1533 | |||
1534 | return 0; | ||
1535 | } | ||
1536 | |||
1537 | static void hdmi_codec_complete(struct device *dev) | ||
1538 | { | ||
1539 | struct hdac_ext_device *edev = to_hda_ext_device(dev); | ||
1426 | struct hdac_hdmi_priv *hdmi = edev->private_data; | 1540 | struct hdac_hdmi_priv *hdmi = edev->private_data; |
1427 | struct hdac_hdmi_pin *pin; | 1541 | struct hdac_hdmi_pin *pin; |
1428 | struct hdac_device *hdac = &edev->hdac; | 1542 | struct hdac_device *hdac = &edev->hdac; |
1429 | struct hdac_bus *bus = hdac->bus; | ||
1430 | int err; | ||
1431 | unsigned long timeout; | ||
1432 | |||
1433 | hdac_hdmi_skl_enable_all_pins(&edev->hdac); | ||
1434 | hdac_hdmi_skl_enable_dp12(&edev->hdac); | ||
1435 | 1543 | ||
1436 | /* Power up afg */ | 1544 | /* Power up afg */ |
1437 | if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) { | 1545 | snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, |
1546 | AC_PWRST_D0); | ||
1438 | 1547 | ||
1439 | snd_hdac_codec_write(hdac, hdac->afg, 0, | 1548 | hdac_hdmi_skl_enable_all_pins(&edev->hdac); |
1440 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | 1549 | hdac_hdmi_skl_enable_dp12(&edev->hdac); |
1441 | |||
1442 | /* Wait till power state is set to D0 */ | ||
1443 | timeout = jiffies + msecs_to_jiffies(1000); | ||
1444 | while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0) | ||
1445 | && time_before(jiffies, timeout)) { | ||
1446 | msleep(50); | ||
1447 | } | ||
1448 | } | ||
1449 | 1550 | ||
1450 | /* | 1551 | /* |
1451 | * As the ELD notify callback request is not entertained while the | 1552 | * As the ELD notify callback request is not entertained while the |
@@ -1455,44 +1556,96 @@ static int hdmi_codec_resume(struct snd_soc_codec *codec) | |||
1455 | list_for_each_entry(pin, &hdmi->pin_list, head) | 1556 | list_for_each_entry(pin, &hdmi->pin_list, head) |
1456 | hdac_hdmi_present_sense(pin, 1); | 1557 | hdac_hdmi_present_sense(pin, 1); |
1457 | 1558 | ||
1458 | /* | 1559 | pm_runtime_put_sync(&edev->hdac.dev); |
1459 | * Codec power is turned ON during controller resume. | ||
1460 | * Turn it OFF here | ||
1461 | */ | ||
1462 | err = snd_hdac_display_power(bus, false); | ||
1463 | if (err < 0) { | ||
1464 | dev_err(bus->dev, | ||
1465 | "Cannot turn OFF display power on i915, err: %d\n", | ||
1466 | err); | ||
1467 | return err; | ||
1468 | } | ||
1469 | |||
1470 | return 0; | ||
1471 | } | 1560 | } |
1472 | #else | 1561 | #else |
1473 | #define hdmi_codec_resume NULL | 1562 | #define hdmi_codec_prepare NULL |
1563 | #define hdmi_codec_complete NULL | ||
1474 | #endif | 1564 | #endif |
1475 | 1565 | ||
1476 | static struct snd_soc_codec_driver hdmi_hda_codec = { | 1566 | static struct snd_soc_codec_driver hdmi_hda_codec = { |
1477 | .probe = hdmi_codec_probe, | 1567 | .probe = hdmi_codec_probe, |
1478 | .remove = hdmi_codec_remove, | 1568 | .remove = hdmi_codec_remove, |
1479 | .resume = hdmi_codec_resume, | ||
1480 | .idle_bias_off = true, | 1569 | .idle_bias_off = true, |
1481 | }; | 1570 | }; |
1482 | 1571 | ||
1572 | static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx, | ||
1573 | unsigned char *chmap) | ||
1574 | { | ||
1575 | struct hdac_ext_device *edev = to_ehdac_device(hdac); | ||
1576 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
1577 | struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); | ||
1578 | struct hdac_hdmi_pin *pin = pcm->pin; | ||
1579 | |||
1580 | /* chmap is already set to 0 in caller */ | ||
1581 | if (!pin) | ||
1582 | return; | ||
1583 | |||
1584 | memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap)); | ||
1585 | } | ||
1586 | |||
1587 | static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx, | ||
1588 | unsigned char *chmap, int prepared) | ||
1589 | { | ||
1590 | struct hdac_ext_device *edev = to_ehdac_device(hdac); | ||
1591 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
1592 | struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); | ||
1593 | struct hdac_hdmi_pin *pin = pcm->pin; | ||
1594 | |||
1595 | mutex_lock(&pin->lock); | ||
1596 | pin->chmap_set = true; | ||
1597 | memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap)); | ||
1598 | if (prepared) | ||
1599 | hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid); | ||
1600 | mutex_unlock(&pin->lock); | ||
1601 | } | ||
1602 | |||
1603 | static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx) | ||
1604 | { | ||
1605 | struct hdac_ext_device *edev = to_ehdac_device(hdac); | ||
1606 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
1607 | struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); | ||
1608 | struct hdac_hdmi_pin *pin = pcm->pin; | ||
1609 | |||
1610 | return pin ? true:false; | ||
1611 | } | ||
1612 | |||
1613 | static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx) | ||
1614 | { | ||
1615 | struct hdac_ext_device *edev = to_ehdac_device(hdac); | ||
1616 | struct hdac_hdmi_priv *hdmi = edev->private_data; | ||
1617 | struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx); | ||
1618 | struct hdac_hdmi_pin *pin = pcm->pin; | ||
1619 | |||
1620 | if (!pin || !pin->eld.eld_valid) | ||
1621 | return 0; | ||
1622 | |||
1623 | return pin->eld.info.spk_alloc; | ||
1624 | } | ||
1625 | |||
1483 | static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) | 1626 | static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) |
1484 | { | 1627 | { |
1485 | struct hdac_device *codec = &edev->hdac; | 1628 | struct hdac_device *codec = &edev->hdac; |
1486 | struct hdac_hdmi_priv *hdmi_priv; | 1629 | struct hdac_hdmi_priv *hdmi_priv; |
1487 | struct snd_soc_dai_driver *hdmi_dais = NULL; | 1630 | struct snd_soc_dai_driver *hdmi_dais = NULL; |
1631 | struct hdac_ext_link *hlink = NULL; | ||
1488 | int num_dais = 0; | 1632 | int num_dais = 0; |
1489 | int ret = 0; | 1633 | int ret = 0; |
1490 | 1634 | ||
1635 | /* hold the ref while we probe */ | ||
1636 | hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); | ||
1637 | snd_hdac_ext_bus_link_get(edev->ebus, hlink); | ||
1638 | |||
1491 | hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); | 1639 | hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); |
1492 | if (hdmi_priv == NULL) | 1640 | if (hdmi_priv == NULL) |
1493 | return -ENOMEM; | 1641 | return -ENOMEM; |
1494 | 1642 | ||
1495 | edev->private_data = hdmi_priv; | 1643 | edev->private_data = hdmi_priv; |
1644 | snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap); | ||
1645 | hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap; | ||
1646 | hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap; | ||
1647 | hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached; | ||
1648 | hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc; | ||
1496 | 1649 | ||
1497 | dev_set_drvdata(&codec->dev, edev); | 1650 | dev_set_drvdata(&codec->dev, edev); |
1498 | 1651 | ||
@@ -1521,8 +1674,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) | |||
1521 | } | 1674 | } |
1522 | 1675 | ||
1523 | /* ASoC specific initialization */ | 1676 | /* ASoC specific initialization */ |
1524 | return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, | 1677 | ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, |
1525 | hdmi_dais, num_dais); | 1678 | hdmi_dais, num_dais); |
1679 | |||
1680 | snd_hdac_ext_bus_link_put(edev->ebus, hlink); | ||
1681 | |||
1682 | return ret; | ||
1526 | } | 1683 | } |
1527 | 1684 | ||
1528 | static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) | 1685 | static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) |
@@ -1561,7 +1718,8 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) | |||
1561 | struct hdac_ext_device *edev = to_hda_ext_device(dev); | 1718 | struct hdac_ext_device *edev = to_hda_ext_device(dev); |
1562 | struct hdac_device *hdac = &edev->hdac; | 1719 | struct hdac_device *hdac = &edev->hdac; |
1563 | struct hdac_bus *bus = hdac->bus; | 1720 | struct hdac_bus *bus = hdac->bus; |
1564 | unsigned long timeout; | 1721 | struct hdac_ext_bus *ebus = hbus_to_ebus(bus); |
1722 | struct hdac_ext_link *hlink = NULL; | ||
1565 | int err; | 1723 | int err; |
1566 | 1724 | ||
1567 | dev_dbg(dev, "Enter: %s\n", __func__); | 1725 | dev_dbg(dev, "Enter: %s\n", __func__); |
@@ -1570,26 +1728,24 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) | |||
1570 | if (!bus) | 1728 | if (!bus) |
1571 | return 0; | 1729 | return 0; |
1572 | 1730 | ||
1573 | /* Power down afg */ | 1731 | /* |
1574 | if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) { | 1732 | * Power down afg. |
1575 | snd_hdac_codec_write(hdac, hdac->afg, 0, | 1733 | * codec_read is preferred over codec_write to set the power state. |
1576 | AC_VERB_SET_POWER_STATE, AC_PWRST_D3); | 1734 | * This way verb is send to set the power state and response |
1577 | 1735 | * is received. So setting power state is ensured without using loop | |
1578 | /* Wait till power state is set to D3 */ | 1736 | * to read the state. |
1579 | timeout = jiffies + msecs_to_jiffies(1000); | 1737 | */ |
1580 | while (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3) | 1738 | snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, |
1581 | && time_before(jiffies, timeout)) { | 1739 | AC_PWRST_D3); |
1582 | |||
1583 | msleep(50); | ||
1584 | } | ||
1585 | } | ||
1586 | |||
1587 | err = snd_hdac_display_power(bus, false); | 1740 | err = snd_hdac_display_power(bus, false); |
1588 | if (err < 0) { | 1741 | if (err < 0) { |
1589 | dev_err(bus->dev, "Cannot turn on display power on i915\n"); | 1742 | dev_err(bus->dev, "Cannot turn on display power on i915\n"); |
1590 | return err; | 1743 | return err; |
1591 | } | 1744 | } |
1592 | 1745 | ||
1746 | hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); | ||
1747 | snd_hdac_ext_bus_link_put(ebus, hlink); | ||
1748 | |||
1593 | return 0; | 1749 | return 0; |
1594 | } | 1750 | } |
1595 | 1751 | ||
@@ -1598,6 +1754,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev) | |||
1598 | struct hdac_ext_device *edev = to_hda_ext_device(dev); | 1754 | struct hdac_ext_device *edev = to_hda_ext_device(dev); |
1599 | struct hdac_device *hdac = &edev->hdac; | 1755 | struct hdac_device *hdac = &edev->hdac; |
1600 | struct hdac_bus *bus = hdac->bus; | 1756 | struct hdac_bus *bus = hdac->bus; |
1757 | struct hdac_ext_bus *ebus = hbus_to_ebus(bus); | ||
1758 | struct hdac_ext_link *hlink = NULL; | ||
1601 | int err; | 1759 | int err; |
1602 | 1760 | ||
1603 | dev_dbg(dev, "Enter: %s\n", __func__); | 1761 | dev_dbg(dev, "Enter: %s\n", __func__); |
@@ -1606,6 +1764,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev) | |||
1606 | if (!bus) | 1764 | if (!bus) |
1607 | return 0; | 1765 | return 0; |
1608 | 1766 | ||
1767 | hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); | ||
1768 | snd_hdac_ext_bus_link_get(ebus, hlink); | ||
1769 | |||
1609 | err = snd_hdac_display_power(bus, true); | 1770 | err = snd_hdac_display_power(bus, true); |
1610 | if (err < 0) { | 1771 | if (err < 0) { |
1611 | dev_err(bus->dev, "Cannot turn on display power on i915\n"); | 1772 | dev_err(bus->dev, "Cannot turn on display power on i915\n"); |
@@ -1616,9 +1777,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev) | |||
1616 | hdac_hdmi_skl_enable_dp12(&edev->hdac); | 1777 | hdac_hdmi_skl_enable_dp12(&edev->hdac); |
1617 | 1778 | ||
1618 | /* Power up afg */ | 1779 | /* Power up afg */ |
1619 | if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) | 1780 | snd_hdac_codec_read(hdac, hdac->afg, 0, AC_VERB_SET_POWER_STATE, |
1620 | snd_hdac_codec_write(hdac, hdac->afg, 0, | 1781 | AC_PWRST_D0); |
1621 | AC_VERB_SET_POWER_STATE, AC_PWRST_D0); | ||
1622 | 1782 | ||
1623 | return 0; | 1783 | return 0; |
1624 | } | 1784 | } |
@@ -1629,6 +1789,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev) | |||
1629 | 1789 | ||
1630 | static const struct dev_pm_ops hdac_hdmi_pm = { | 1790 | static const struct dev_pm_ops hdac_hdmi_pm = { |
1631 | SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) | 1791 | SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) |
1792 | .prepare = hdmi_codec_prepare, | ||
1793 | .complete = hdmi_codec_complete, | ||
1632 | }; | 1794 | }; |
1633 | 1795 | ||
1634 | static const struct hda_device_id hdmi_list[] = { | 1796 | static const struct hda_device_id hdmi_list[] = { |
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c new file mode 100644 index 000000000000..8e36e883e453 --- /dev/null +++ b/sound/soc/codecs/hdmi-codec.c | |||
@@ -0,0 +1,432 @@ | |||
1 | /* | ||
2 | * ALSA SoC codec for HDMI encoder drivers | ||
3 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ | ||
4 | * Author: Jyri Sarha <jsarha@ti.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <sound/pcm_drm_eld.h> | ||
22 | #include <sound/hdmi-codec.h> | ||
23 | #include <sound/pcm_iec958.h> | ||
24 | |||
25 | #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */ | ||
26 | |||
27 | struct hdmi_codec_priv { | ||
28 | struct hdmi_codec_pdata hcd; | ||
29 | struct snd_soc_dai_driver *daidrv; | ||
30 | struct hdmi_codec_daifmt daifmt[2]; | ||
31 | struct mutex current_stream_lock; | ||
32 | struct snd_pcm_substream *current_stream; | ||
33 | struct snd_pcm_hw_constraint_list ratec; | ||
34 | uint8_t eld[MAX_ELD_BYTES]; | ||
35 | }; | ||
36 | |||
37 | static const struct snd_soc_dapm_widget hdmi_widgets[] = { | ||
38 | SND_SOC_DAPM_OUTPUT("TX"), | ||
39 | }; | ||
40 | |||
41 | static const struct snd_soc_dapm_route hdmi_routes[] = { | ||
42 | { "TX", NULL, "Playback" }, | ||
43 | }; | ||
44 | |||
45 | enum { | ||
46 | DAI_ID_I2S = 0, | ||
47 | DAI_ID_SPDIF, | ||
48 | }; | ||
49 | |||
50 | static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, | ||
51 | struct snd_ctl_elem_info *uinfo) | ||
52 | { | ||
53 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
54 | struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); | ||
55 | |||
56 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
57 | uinfo->count = sizeof(hcp->eld); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, | ||
63 | struct snd_ctl_elem_value *ucontrol) | ||
64 | { | ||
65 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
66 | struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); | ||
67 | |||
68 | memcpy(ucontrol->value.bytes.data, hcp->eld, sizeof(hcp->eld)); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static const struct snd_kcontrol_new hdmi_controls[] = { | ||
74 | { | ||
75 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | ||
76 | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | ||
77 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
78 | .name = "ELD", | ||
79 | .info = hdmi_eld_ctl_info, | ||
80 | .get = hdmi_eld_ctl_get, | ||
81 | }, | ||
82 | }; | ||
83 | |||
84 | static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, | ||
85 | struct snd_soc_dai *dai) | ||
86 | { | ||
87 | struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); | ||
88 | int ret = 0; | ||
89 | |||
90 | mutex_lock(&hcp->current_stream_lock); | ||
91 | if (!hcp->current_stream) { | ||
92 | hcp->current_stream = substream; | ||
93 | } else if (hcp->current_stream != substream) { | ||
94 | dev_err(dai->dev, "Only one simultaneous stream supported!\n"); | ||
95 | ret = -EINVAL; | ||
96 | } | ||
97 | mutex_unlock(&hcp->current_stream_lock); | ||
98 | |||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static int hdmi_codec_startup(struct snd_pcm_substream *substream, | ||
103 | struct snd_soc_dai *dai) | ||
104 | { | ||
105 | struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); | ||
106 | int ret = 0; | ||
107 | |||
108 | dev_dbg(dai->dev, "%s()\n", __func__); | ||
109 | |||
110 | ret = hdmi_codec_new_stream(substream, dai); | ||
111 | if (ret) | ||
112 | return ret; | ||
113 | |||
114 | if (hcp->hcd.ops->audio_startup) { | ||
115 | ret = hcp->hcd.ops->audio_startup(dai->dev->parent); | ||
116 | if (ret) { | ||
117 | mutex_lock(&hcp->current_stream_lock); | ||
118 | hcp->current_stream = NULL; | ||
119 | mutex_unlock(&hcp->current_stream_lock); | ||
120 | return ret; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | if (hcp->hcd.ops->get_eld) { | ||
125 | ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->eld, | ||
126 | sizeof(hcp->eld)); | ||
127 | |||
128 | if (!ret) { | ||
129 | ret = snd_pcm_hw_constraint_eld(substream->runtime, | ||
130 | hcp->eld); | ||
131 | if (ret) | ||
132 | return ret; | ||
133 | } | ||
134 | } | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, | ||
139 | struct snd_soc_dai *dai) | ||
140 | { | ||
141 | struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); | ||
142 | |||
143 | dev_dbg(dai->dev, "%s()\n", __func__); | ||
144 | |||
145 | WARN_ON(hcp->current_stream != substream); | ||
146 | |||
147 | hcp->hcd.ops->audio_shutdown(dai->dev->parent); | ||
148 | |||
149 | mutex_lock(&hcp->current_stream_lock); | ||
150 | hcp->current_stream = NULL; | ||
151 | mutex_unlock(&hcp->current_stream_lock); | ||
152 | } | ||
153 | |||
154 | static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, | ||
155 | struct snd_pcm_hw_params *params, | ||
156 | struct snd_soc_dai *dai) | ||
157 | { | ||
158 | struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); | ||
159 | struct hdmi_codec_params hp = { | ||
160 | .iec = { | ||
161 | .status = { 0 }, | ||
162 | .subcode = { 0 }, | ||
163 | .pad = 0, | ||
164 | .dig_subframe = { 0 }, | ||
165 | } | ||
166 | }; | ||
167 | int ret; | ||
168 | |||
169 | dev_dbg(dai->dev, "%s() width %d rate %d channels %d\n", __func__, | ||
170 | params_width(params), params_rate(params), | ||
171 | params_channels(params)); | ||
172 | |||
173 | if (params_width(params) > 24) | ||
174 | params->msbits = 24; | ||
175 | |||
176 | ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, | ||
177 | sizeof(hp.iec.status)); | ||
178 | if (ret < 0) { | ||
179 | dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", | ||
180 | ret); | ||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | ret = hdmi_codec_new_stream(substream, dai); | ||
185 | if (ret) | ||
186 | return ret; | ||
187 | |||
188 | hdmi_audio_infoframe_init(&hp.cea); | ||
189 | hp.cea.channels = params_channels(params); | ||
190 | hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; | ||
191 | hp.cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; | ||
192 | hp.cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; | ||
193 | |||
194 | hp.sample_width = params_width(params); | ||
195 | hp.sample_rate = params_rate(params); | ||
196 | hp.channels = params_channels(params); | ||
197 | |||
198 | return hcp->hcd.ops->hw_params(dai->dev->parent, &hcp->daifmt[dai->id], | ||
199 | &hp); | ||
200 | } | ||
201 | |||
202 | static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, | ||
203 | unsigned int fmt) | ||
204 | { | ||
205 | struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); | ||
206 | struct hdmi_codec_daifmt cf = { 0 }; | ||
207 | int ret = 0; | ||
208 | |||
209 | dev_dbg(dai->dev, "%s()\n", __func__); | ||
210 | |||
211 | if (dai->id == DAI_ID_SPDIF) { | ||
212 | cf.fmt = HDMI_SPDIF; | ||
213 | } else { | ||
214 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
215 | case SND_SOC_DAIFMT_CBM_CFM: | ||
216 | cf.bit_clk_master = 1; | ||
217 | cf.frame_clk_master = 1; | ||
218 | break; | ||
219 | case SND_SOC_DAIFMT_CBS_CFM: | ||
220 | cf.frame_clk_master = 1; | ||
221 | break; | ||
222 | case SND_SOC_DAIFMT_CBM_CFS: | ||
223 | cf.bit_clk_master = 1; | ||
224 | break; | ||
225 | case SND_SOC_DAIFMT_CBS_CFS: | ||
226 | break; | ||
227 | default: | ||
228 | return -EINVAL; | ||
229 | } | ||
230 | |||
231 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
232 | case SND_SOC_DAIFMT_NB_NF: | ||
233 | break; | ||
234 | case SND_SOC_DAIFMT_NB_IF: | ||
235 | cf.frame_clk_inv = 1; | ||
236 | break; | ||
237 | case SND_SOC_DAIFMT_IB_NF: | ||
238 | cf.bit_clk_inv = 1; | ||
239 | break; | ||
240 | case SND_SOC_DAIFMT_IB_IF: | ||
241 | cf.frame_clk_inv = 1; | ||
242 | cf.bit_clk_inv = 1; | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
247 | case SND_SOC_DAIFMT_I2S: | ||
248 | cf.fmt = HDMI_I2S; | ||
249 | break; | ||
250 | case SND_SOC_DAIFMT_DSP_A: | ||
251 | cf.fmt = HDMI_DSP_A; | ||
252 | break; | ||
253 | case SND_SOC_DAIFMT_DSP_B: | ||
254 | cf.fmt = HDMI_DSP_B; | ||
255 | break; | ||
256 | case SND_SOC_DAIFMT_RIGHT_J: | ||
257 | cf.fmt = HDMI_RIGHT_J; | ||
258 | break; | ||
259 | case SND_SOC_DAIFMT_LEFT_J: | ||
260 | cf.fmt = HDMI_LEFT_J; | ||
261 | break; | ||
262 | case SND_SOC_DAIFMT_AC97: | ||
263 | cf.fmt = HDMI_AC97; | ||
264 | break; | ||
265 | default: | ||
266 | dev_err(dai->dev, "Invalid DAI interface format\n"); | ||
267 | return -EINVAL; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | hcp->daifmt[dai->id] = cf; | ||
272 | |||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) | ||
277 | { | ||
278 | struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); | ||
279 | |||
280 | dev_dbg(dai->dev, "%s()\n", __func__); | ||
281 | |||
282 | if (hcp->hcd.ops->digital_mute) | ||
283 | return hcp->hcd.ops->digital_mute(dai->dev->parent, mute); | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static const struct snd_soc_dai_ops hdmi_dai_ops = { | ||
289 | .startup = hdmi_codec_startup, | ||
290 | .shutdown = hdmi_codec_shutdown, | ||
291 | .hw_params = hdmi_codec_hw_params, | ||
292 | .set_fmt = hdmi_codec_set_fmt, | ||
293 | .digital_mute = hdmi_codec_digital_mute, | ||
294 | }; | ||
295 | |||
296 | |||
297 | #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
298 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | ||
299 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ | ||
300 | SNDRV_PCM_RATE_192000) | ||
301 | |||
302 | #define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ | ||
303 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ | ||
304 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ | ||
305 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | ||
306 | |||
307 | /* | ||
308 | * This list is only for formats allowed on the I2S bus. So there is | ||
309 | * some formats listed that are not supported by HDMI interface. For | ||
310 | * instance allowing the 32-bit formats enables 24-precision with CPU | ||
311 | * DAIs that do not support 24-bit formats. If the extra formats cause | ||
312 | * problems, we should add the video side driver an option to disable | ||
313 | * them. | ||
314 | */ | ||
315 | #define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ | ||
316 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ | ||
317 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ | ||
318 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ | ||
319 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) | ||
320 | |||
321 | static struct snd_soc_dai_driver hdmi_i2s_dai = { | ||
322 | .name = "i2s-hifi", | ||
323 | .id = DAI_ID_I2S, | ||
324 | .playback = { | ||
325 | .stream_name = "Playback", | ||
326 | .channels_min = 2, | ||
327 | .channels_max = 8, | ||
328 | .rates = HDMI_RATES, | ||
329 | .formats = I2S_FORMATS, | ||
330 | .sig_bits = 24, | ||
331 | }, | ||
332 | .ops = &hdmi_dai_ops, | ||
333 | }; | ||
334 | |||
335 | static const struct snd_soc_dai_driver hdmi_spdif_dai = { | ||
336 | .name = "spdif-hifi", | ||
337 | .id = DAI_ID_SPDIF, | ||
338 | .playback = { | ||
339 | .stream_name = "Playback", | ||
340 | .channels_min = 2, | ||
341 | .channels_max = 2, | ||
342 | .rates = HDMI_RATES, | ||
343 | .formats = SPDIF_FORMATS, | ||
344 | }, | ||
345 | .ops = &hdmi_dai_ops, | ||
346 | }; | ||
347 | |||
348 | static struct snd_soc_codec_driver hdmi_codec = { | ||
349 | .controls = hdmi_controls, | ||
350 | .num_controls = ARRAY_SIZE(hdmi_controls), | ||
351 | .dapm_widgets = hdmi_widgets, | ||
352 | .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), | ||
353 | .dapm_routes = hdmi_routes, | ||
354 | .num_dapm_routes = ARRAY_SIZE(hdmi_routes), | ||
355 | }; | ||
356 | |||
357 | static int hdmi_codec_probe(struct platform_device *pdev) | ||
358 | { | ||
359 | struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; | ||
360 | struct device *dev = &pdev->dev; | ||
361 | struct hdmi_codec_priv *hcp; | ||
362 | int dai_count, i = 0; | ||
363 | int ret; | ||
364 | |||
365 | dev_dbg(dev, "%s()\n", __func__); | ||
366 | |||
367 | if (!hcd) { | ||
368 | dev_err(dev, "%s: No plalform data\n", __func__); | ||
369 | return -EINVAL; | ||
370 | } | ||
371 | |||
372 | dai_count = hcd->i2s + hcd->spdif; | ||
373 | if (dai_count < 1 || !hcd->ops || !hcd->ops->hw_params || | ||
374 | !hcd->ops->audio_shutdown) { | ||
375 | dev_err(dev, "%s: Invalid parameters\n", __func__); | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | |||
379 | hcp = devm_kzalloc(dev, sizeof(*hcp), GFP_KERNEL); | ||
380 | if (!hcp) | ||
381 | return -ENOMEM; | ||
382 | |||
383 | hcp->hcd = *hcd; | ||
384 | mutex_init(&hcp->current_stream_lock); | ||
385 | |||
386 | hcp->daidrv = devm_kzalloc(dev, dai_count * sizeof(*hcp->daidrv), | ||
387 | GFP_KERNEL); | ||
388 | if (!hcp->daidrv) | ||
389 | return -ENOMEM; | ||
390 | |||
391 | if (hcd->i2s) { | ||
392 | hcp->daidrv[i] = hdmi_i2s_dai; | ||
393 | hcp->daidrv[i].playback.channels_max = | ||
394 | hcd->max_i2s_channels; | ||
395 | i++; | ||
396 | } | ||
397 | |||
398 | if (hcd->spdif) | ||
399 | hcp->daidrv[i] = hdmi_spdif_dai; | ||
400 | |||
401 | ret = snd_soc_register_codec(dev, &hdmi_codec, hcp->daidrv, | ||
402 | dai_count); | ||
403 | if (ret) { | ||
404 | dev_err(dev, "%s: snd_soc_register_codec() failed (%d)\n", | ||
405 | __func__, ret); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | dev_set_drvdata(dev, hcp); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int hdmi_codec_remove(struct platform_device *pdev) | ||
414 | { | ||
415 | snd_soc_unregister_codec(&pdev->dev); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static struct platform_driver hdmi_codec_driver = { | ||
420 | .driver = { | ||
421 | .name = HDMI_CODEC_DRV_NAME, | ||
422 | }, | ||
423 | .probe = hdmi_codec_probe, | ||
424 | .remove = hdmi_codec_remove, | ||
425 | }; | ||
426 | |||
427 | module_platform_driver(hdmi_codec_driver); | ||
428 | |||
429 | MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>"); | ||
430 | MODULE_DESCRIPTION("HDMI Audio Codec Driver"); | ||
431 | MODULE_LICENSE("GPL"); | ||
432 | MODULE_ALIAS("platform:" HDMI_CODEC_DRV_NAME); | ||
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c new file mode 100644 index 000000000000..cf0a39bb631a --- /dev/null +++ b/sound/soc/codecs/max98371.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* | ||
2 | * max98371.c -- ALSA SoC Stereo MAX98371 driver | ||
3 | * | ||
4 | * Copyright 2015-16 Maxim Integrated Products | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/i2c.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/regmap.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/pcm_params.h> | ||
17 | #include <sound/soc.h> | ||
18 | #include <sound/tlv.h> | ||
19 | #include "max98371.h" | ||
20 | |||
21 | static const char *const monomix_text[] = { | ||
22 | "Left", "Right", "LeftRightDiv2", | ||
23 | }; | ||
24 | |||
25 | static const char *const hpf_cutoff_txt[] = { | ||
26 | "Disable", "DC Block", "50Hz", | ||
27 | "100Hz", "200Hz", "400Hz", "800Hz", | ||
28 | }; | ||
29 | |||
30 | static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0, | ||
31 | monomix_text); | ||
32 | |||
33 | static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0, | ||
34 | hpf_cutoff_txt); | ||
35 | |||
36 | static const DECLARE_TLV_DB_RANGE(max98371_dht_min_gain, | ||
37 | 0, 1, TLV_DB_SCALE_ITEM(537, 66, 0), | ||
38 | 2, 3, TLV_DB_SCALE_ITEM(677, 82, 0), | ||
39 | 4, 5, TLV_DB_SCALE_ITEM(852, 104, 0), | ||
40 | 6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0), | ||
41 | 8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0), | ||
42 | 10, 11, TLV_DB_SCALE_ITEM(1699, 101, 0), | ||
43 | ); | ||
44 | |||
45 | static const DECLARE_TLV_DB_RANGE(max98371_dht_max_gain, | ||
46 | 0, 1, TLV_DB_SCALE_ITEM(537, 66, 0), | ||
47 | 2, 3, TLV_DB_SCALE_ITEM(677, 82, 0), | ||
48 | 4, 5, TLV_DB_SCALE_ITEM(852, 104, 0), | ||
49 | 6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0), | ||
50 | 8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0), | ||
51 | 10, 11, TLV_DB_SCALE_ITEM(1699, 208, 0), | ||
52 | ); | ||
53 | |||
54 | static const DECLARE_TLV_DB_RANGE(max98371_dht_rot_gain, | ||
55 | 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0), | ||
56 | 2, 6, TLV_DB_SCALE_ITEM(-100, -100, 0), | ||
57 | 7, 8, TLV_DB_SCALE_ITEM(-800, -200, 0), | ||
58 | 9, 11, TLV_DB_SCALE_ITEM(-1200, -300, 0), | ||
59 | 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0), | ||
60 | 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), | ||
61 | ); | ||
62 | |||
63 | static const struct reg_default max98371_reg[] = { | ||
64 | { 0x01, 0x00 }, | ||
65 | { 0x02, 0x00 }, | ||
66 | { 0x03, 0x00 }, | ||
67 | { 0x04, 0x00 }, | ||
68 | { 0x05, 0x00 }, | ||
69 | { 0x06, 0x00 }, | ||
70 | { 0x07, 0x00 }, | ||
71 | { 0x08, 0x00 }, | ||
72 | { 0x09, 0x00 }, | ||
73 | { 0x0A, 0x00 }, | ||
74 | { 0x10, 0x06 }, | ||
75 | { 0x11, 0x08 }, | ||
76 | { 0x14, 0x80 }, | ||
77 | { 0x15, 0x00 }, | ||
78 | { 0x16, 0x00 }, | ||
79 | { 0x18, 0x00 }, | ||
80 | { 0x19, 0x00 }, | ||
81 | { 0x1C, 0x00 }, | ||
82 | { 0x1D, 0x00 }, | ||
83 | { 0x1E, 0x00 }, | ||
84 | { 0x1F, 0x00 }, | ||
85 | { 0x20, 0x00 }, | ||
86 | { 0x21, 0x00 }, | ||
87 | { 0x22, 0x00 }, | ||
88 | { 0x23, 0x00 }, | ||
89 | { 0x24, 0x00 }, | ||
90 | { 0x25, 0x00 }, | ||
91 | { 0x26, 0x00 }, | ||
92 | { 0x27, 0x00 }, | ||
93 | { 0x28, 0x00 }, | ||
94 | { 0x29, 0x00 }, | ||
95 | { 0x2A, 0x00 }, | ||
96 | { 0x2B, 0x00 }, | ||
97 | { 0x2C, 0x00 }, | ||
98 | { 0x2D, 0x00 }, | ||
99 | { 0x2E, 0x0B }, | ||
100 | { 0x31, 0x00 }, | ||
101 | { 0x32, 0x18 }, | ||
102 | { 0x33, 0x00 }, | ||
103 | { 0x34, 0x00 }, | ||
104 | { 0x36, 0x00 }, | ||
105 | { 0x37, 0x00 }, | ||
106 | { 0x38, 0x00 }, | ||
107 | { 0x39, 0x00 }, | ||
108 | { 0x3A, 0x00 }, | ||
109 | { 0x3B, 0x00 }, | ||
110 | { 0x3C, 0x00 }, | ||
111 | { 0x3D, 0x00 }, | ||
112 | { 0x3E, 0x00 }, | ||
113 | { 0x3F, 0x00 }, | ||
114 | { 0x40, 0x00 }, | ||
115 | { 0x41, 0x00 }, | ||
116 | { 0x42, 0x00 }, | ||
117 | { 0x43, 0x00 }, | ||
118 | { 0x4A, 0x00 }, | ||
119 | { 0x4B, 0x00 }, | ||
120 | { 0x4C, 0x00 }, | ||
121 | { 0x4D, 0x00 }, | ||
122 | { 0x4E, 0x00 }, | ||
123 | { 0x50, 0x00 }, | ||
124 | { 0x51, 0x00 }, | ||
125 | { 0x55, 0x00 }, | ||
126 | { 0x58, 0x00 }, | ||
127 | { 0x59, 0x00 }, | ||
128 | { 0x5C, 0x00 }, | ||
129 | { 0xFF, 0x43 }, | ||
130 | }; | ||
131 | |||
132 | static bool max98371_volatile_register(struct device *dev, unsigned int reg) | ||
133 | { | ||
134 | switch (reg) { | ||
135 | case MAX98371_IRQ_CLEAR1: | ||
136 | case MAX98371_IRQ_CLEAR2: | ||
137 | case MAX98371_IRQ_CLEAR3: | ||
138 | case MAX98371_VERSION: | ||
139 | return true; | ||
140 | default: | ||
141 | return false; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static bool max98371_readable_register(struct device *dev, unsigned int reg) | ||
146 | { | ||
147 | switch (reg) { | ||
148 | case MAX98371_SOFT_RESET: | ||
149 | return false; | ||
150 | default: | ||
151 | return true; | ||
152 | } | ||
153 | }; | ||
154 | |||
155 | static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv, | ||
156 | 0, 7, TLV_DB_SCALE_ITEM(0, 50, 0), | ||
157 | 8, 10, TLV_DB_SCALE_ITEM(400, 100, 0) | ||
158 | ); | ||
159 | |||
160 | static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv, | ||
161 | 0, 11, TLV_DB_SCALE_ITEM(950, 100, 0), | ||
162 | ); | ||
163 | |||
164 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1); | ||
165 | |||
166 | static const struct snd_kcontrol_new max98371_snd_controls[] = { | ||
167 | SOC_SINGLE_TLV("Speaker Volume", MAX98371_GAIN, | ||
168 | MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0, | ||
169 | max98371_gain_tlv), | ||
170 | SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0, | ||
171 | (1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv), | ||
172 | SOC_SINGLE_TLV("Speaker DHT Max Volume", MAX98371_GAIN, | ||
173 | 0, (1<<MAX98371_DHT_MAX_WIDTH)-1, 0, | ||
174 | max98371_dht_max_gain), | ||
175 | SOC_SINGLE_TLV("Speaker DHT Min Volume", MAX98371_DHT_GAIN, | ||
176 | 0, (1<<MAX98371_DHT_GAIN_WIDTH)-1, 0, | ||
177 | max98371_dht_min_gain), | ||
178 | SOC_SINGLE_TLV("Speaker DHT Rotation Volume", MAX98371_DHT_GAIN, | ||
179 | 0, (1<<MAX98371_DHT_ROT_WIDTH)-1, 0, | ||
180 | max98371_dht_rot_gain), | ||
181 | SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0), | ||
182 | SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0), | ||
183 | SOC_ENUM("Monomix Select", max98371_monomix), | ||
184 | SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff), | ||
185 | }; | ||
186 | |||
187 | static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai, | ||
188 | unsigned int fmt) | ||
189 | { | ||
190 | struct snd_soc_codec *codec = codec_dai->codec; | ||
191 | struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec); | ||
192 | unsigned int val = 0; | ||
193 | |||
194 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
195 | case SND_SOC_DAIFMT_CBS_CFS: | ||
196 | break; | ||
197 | default: | ||
198 | dev_err(codec->dev, "DAI clock mode unsupported"); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
203 | case SND_SOC_DAIFMT_I2S: | ||
204 | val |= 0; | ||
205 | break; | ||
206 | case SND_SOC_DAIFMT_RIGHT_J: | ||
207 | val |= MAX98371_DAI_RIGHT; | ||
208 | break; | ||
209 | case SND_SOC_DAIFMT_LEFT_J: | ||
210 | val |= MAX98371_DAI_LEFT; | ||
211 | break; | ||
212 | default: | ||
213 | dev_err(codec->dev, "DAI wrong mode unsupported"); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
217 | MAX98371_FMT_MODE_MASK, val); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int max98371_dai_hw_params(struct snd_pcm_substream *substream, | ||
222 | struct snd_pcm_hw_params *params, | ||
223 | struct snd_soc_dai *dai) | ||
224 | { | ||
225 | struct snd_soc_codec *codec = dai->codec; | ||
226 | struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec); | ||
227 | int blr_clk_ratio, ch_size, channels = params_channels(params); | ||
228 | int rate = params_rate(params); | ||
229 | |||
230 | switch (params_format(params)) { | ||
231 | case SNDRV_PCM_FORMAT_S8: | ||
232 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
233 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16); | ||
234 | ch_size = 8; | ||
235 | break; | ||
236 | case SNDRV_PCM_FORMAT_S16_LE: | ||
237 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
238 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16); | ||
239 | ch_size = 16; | ||
240 | break; | ||
241 | case SNDRV_PCM_FORMAT_S24_LE: | ||
242 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
243 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32); | ||
244 | ch_size = 24; | ||
245 | break; | ||
246 | case SNDRV_PCM_FORMAT_S32_LE: | ||
247 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
248 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32); | ||
249 | ch_size = 32; | ||
250 | break; | ||
251 | default: | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | /* BCLK/LRCLK ratio calculation */ | ||
256 | blr_clk_ratio = channels * ch_size; | ||
257 | switch (blr_clk_ratio) { | ||
258 | case 32: | ||
259 | regmap_update_bits(max98371->regmap, | ||
260 | MAX98371_DAI_CLK, | ||
261 | MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32); | ||
262 | break; | ||
263 | case 48: | ||
264 | regmap_update_bits(max98371->regmap, | ||
265 | MAX98371_DAI_CLK, | ||
266 | MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48); | ||
267 | break; | ||
268 | case 64: | ||
269 | regmap_update_bits(max98371->regmap, | ||
270 | MAX98371_DAI_CLK, | ||
271 | MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64); | ||
272 | break; | ||
273 | default: | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | |||
277 | switch (rate) { | ||
278 | case 32000: | ||
279 | regmap_update_bits(max98371->regmap, | ||
280 | MAX98371_SPK_SR, | ||
281 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32); | ||
282 | break; | ||
283 | case 44100: | ||
284 | regmap_update_bits(max98371->regmap, | ||
285 | MAX98371_SPK_SR, | ||
286 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44); | ||
287 | break; | ||
288 | case 48000: | ||
289 | regmap_update_bits(max98371->regmap, | ||
290 | MAX98371_SPK_SR, | ||
291 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48); | ||
292 | break; | ||
293 | case 88200: | ||
294 | regmap_update_bits(max98371->regmap, | ||
295 | MAX98371_SPK_SR, | ||
296 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88); | ||
297 | break; | ||
298 | case 96000: | ||
299 | regmap_update_bits(max98371->regmap, | ||
300 | MAX98371_SPK_SR, | ||
301 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96); | ||
302 | break; | ||
303 | default: | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | /* enabling both the RX channels*/ | ||
308 | regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC, | ||
309 | MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1); | ||
310 | regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL, | ||
311 | MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = { | ||
316 | SND_SOC_DAPM_DAC("DAC", NULL, MAX98371_SPK_ENABLE, 0, 0), | ||
317 | SND_SOC_DAPM_SUPPLY("Global Enable", MAX98371_GLOBAL_ENABLE, | ||
318 | 0, 0, NULL, 0), | ||
319 | SND_SOC_DAPM_OUTPUT("SPK_OUT"), | ||
320 | }; | ||
321 | |||
322 | static const struct snd_soc_dapm_route max98371_audio_map[] = { | ||
323 | {"DAC", NULL, "HiFi Playback"}, | ||
324 | {"SPK_OUT", NULL, "DAC"}, | ||
325 | {"SPK_OUT", NULL, "Global Enable"}, | ||
326 | }; | ||
327 | |||
328 | #define MAX98371_RATES SNDRV_PCM_RATE_8000_48000 | ||
329 | #define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
330 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) | ||
331 | |||
332 | static const struct snd_soc_dai_ops max98371_dai_ops = { | ||
333 | .set_fmt = max98371_dai_set_fmt, | ||
334 | .hw_params = max98371_dai_hw_params, | ||
335 | }; | ||
336 | |||
337 | static struct snd_soc_dai_driver max98371_dai[] = { | ||
338 | { | ||
339 | .name = "max98371-aif1", | ||
340 | .playback = { | ||
341 | .stream_name = "HiFi Playback", | ||
342 | .channels_min = 1, | ||
343 | .channels_max = 2, | ||
344 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
345 | .formats = MAX98371_FORMATS, | ||
346 | }, | ||
347 | .ops = &max98371_dai_ops, | ||
348 | } | ||
349 | }; | ||
350 | |||
351 | static const struct snd_soc_codec_driver max98371_codec = { | ||
352 | .controls = max98371_snd_controls, | ||
353 | .num_controls = ARRAY_SIZE(max98371_snd_controls), | ||
354 | .dapm_routes = max98371_audio_map, | ||
355 | .num_dapm_routes = ARRAY_SIZE(max98371_audio_map), | ||
356 | .dapm_widgets = max98371_dapm_widgets, | ||
357 | .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), | ||
358 | }; | ||
359 | |||
360 | static const struct regmap_config max98371_regmap = { | ||
361 | .reg_bits = 8, | ||
362 | .val_bits = 8, | ||
363 | .max_register = MAX98371_VERSION, | ||
364 | .reg_defaults = max98371_reg, | ||
365 | .num_reg_defaults = ARRAY_SIZE(max98371_reg), | ||
366 | .volatile_reg = max98371_volatile_register, | ||
367 | .readable_reg = max98371_readable_register, | ||
368 | .cache_type = REGCACHE_RBTREE, | ||
369 | }; | ||
370 | |||
371 | static int max98371_i2c_probe(struct i2c_client *i2c, | ||
372 | const struct i2c_device_id *id) | ||
373 | { | ||
374 | struct max98371_priv *max98371; | ||
375 | int ret, reg; | ||
376 | |||
377 | max98371 = devm_kzalloc(&i2c->dev, | ||
378 | sizeof(*max98371), GFP_KERNEL); | ||
379 | if (!max98371) | ||
380 | return -ENOMEM; | ||
381 | |||
382 | i2c_set_clientdata(i2c, max98371); | ||
383 | max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap); | ||
384 | if (IS_ERR(max98371->regmap)) { | ||
385 | ret = PTR_ERR(max98371->regmap); | ||
386 | dev_err(&i2c->dev, | ||
387 | "Failed to allocate regmap: %d\n", ret); | ||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | ret = regmap_read(max98371->regmap, MAX98371_VERSION, ®); | ||
392 | if (ret < 0) { | ||
393 | dev_info(&i2c->dev, "device error %d\n", ret); | ||
394 | return ret; | ||
395 | } | ||
396 | dev_info(&i2c->dev, "device version %x\n", reg); | ||
397 | |||
398 | ret = snd_soc_register_codec(&i2c->dev, &max98371_codec, | ||
399 | max98371_dai, ARRAY_SIZE(max98371_dai)); | ||
400 | if (ret < 0) { | ||
401 | dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); | ||
402 | return ret; | ||
403 | } | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | static int max98371_i2c_remove(struct i2c_client *client) | ||
408 | { | ||
409 | snd_soc_unregister_codec(&client->dev); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static const struct i2c_device_id max98371_i2c_id[] = { | ||
414 | { "max98371", 0 }, | ||
415 | }; | ||
416 | |||
417 | MODULE_DEVICE_TABLE(i2c, max98371_i2c_id); | ||
418 | |||
419 | static const struct of_device_id max98371_of_match[] = { | ||
420 | { .compatible = "maxim,max98371", }, | ||
421 | { } | ||
422 | }; | ||
423 | MODULE_DEVICE_TABLE(of, max98371_of_match); | ||
424 | |||
425 | static struct i2c_driver max98371_i2c_driver = { | ||
426 | .driver = { | ||
427 | .name = "max98371", | ||
428 | .owner = THIS_MODULE, | ||
429 | .pm = NULL, | ||
430 | .of_match_table = of_match_ptr(max98371_of_match), | ||
431 | }, | ||
432 | .probe = max98371_i2c_probe, | ||
433 | .remove = max98371_i2c_remove, | ||
434 | .id_table = max98371_i2c_id, | ||
435 | }; | ||
436 | |||
437 | module_i2c_driver(max98371_i2c_driver); | ||
438 | |||
439 | MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>"); | ||
440 | MODULE_DESCRIPTION("ALSA SoC MAX98371 driver"); | ||
441 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h new file mode 100644 index 000000000000..9f6330964d98 --- /dev/null +++ b/sound/soc/codecs/max98371.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * max98371.h -- MAX98371 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2011-2012 Maxim Integrated Products | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _MAX98371_H | ||
12 | #define _MAX98371_H | ||
13 | |||
14 | #define MAX98371_IRQ_CLEAR1 0x01 | ||
15 | #define MAX98371_IRQ_CLEAR2 0x02 | ||
16 | #define MAX98371_IRQ_CLEAR3 0x03 | ||
17 | #define MAX98371_DAI_CLK 0x10 | ||
18 | #define MAX98371_DAI_BSEL_MASK 0xF | ||
19 | #define MAX98371_DAI_BSEL_32 2 | ||
20 | #define MAX98371_DAI_BSEL_48 3 | ||
21 | #define MAX98371_DAI_BSEL_64 4 | ||
22 | #define MAX98371_SPK_SR 0x11 | ||
23 | #define MAX98371_SPK_SR_MASK 0xF | ||
24 | #define MAX98371_SPK_SR_32 6 | ||
25 | #define MAX98371_SPK_SR_44 7 | ||
26 | #define MAX98371_SPK_SR_48 8 | ||
27 | #define MAX98371_SPK_SR_88 10 | ||
28 | #define MAX98371_SPK_SR_96 11 | ||
29 | #define MAX98371_DAI_CHANNEL 0x15 | ||
30 | #define MAX98371_CHANNEL_MASK 0x3 | ||
31 | #define MAX98371_MONOMIX_SRC 0x18 | ||
32 | #define MAX98371_MONOMIX_CFG 0x19 | ||
33 | #define MAX98371_HPF 0x1C | ||
34 | #define MAX98371_MONOMIX_SRC_MASK 0xFF | ||
35 | #define MONOMIX_RX_0_1 ((0x1)<<(4)) | ||
36 | #define M98371_DAI_CHANNEL_I2S 0x3 | ||
37 | #define MAX98371_DIGITAL_GAIN 0x2D | ||
38 | #define MAX98371_DIGITAL_GAIN_WIDTH 0x7 | ||
39 | #define MAX98371_GAIN 0x2E | ||
40 | #define MAX98371_GAIN_SHIFT 0x4 | ||
41 | #define MAX98371_GAIN_WIDTH 0x4 | ||
42 | #define MAX98371_DHT_MAX_WIDTH 4 | ||
43 | #define MAX98371_FMT 0x14 | ||
44 | #define MAX98371_CHANSZ_WIDTH 6 | ||
45 | #define MAX98371_FMT_MASK ((0x3)<<(MAX98371_CHANSZ_WIDTH)) | ||
46 | #define MAX98371_FMT_MODE_MASK ((0x7)<<(3)) | ||
47 | #define MAX98371_DAI_LEFT ((0x1)<<(3)) | ||
48 | #define MAX98371_DAI_RIGHT ((0x2)<<(3)) | ||
49 | #define MAX98371_DAI_CHANSZ_16 ((1)<<(MAX98371_CHANSZ_WIDTH)) | ||
50 | #define MAX98371_DAI_CHANSZ_24 ((2)<<(MAX98371_CHANSZ_WIDTH)) | ||
51 | #define MAX98371_DAI_CHANSZ_32 ((3)<<(MAX98371_CHANSZ_WIDTH)) | ||
52 | #define MAX98371_DHT 0x32 | ||
53 | #define MAX98371_DHT_STEP 0x3 | ||
54 | #define MAX98371_DHT_GAIN 0x31 | ||
55 | #define MAX98371_DHT_GAIN_WIDTH 0x4 | ||
56 | #define MAX98371_DHT_ROT_WIDTH 0x4 | ||
57 | #define MAX98371_SPK_ENABLE 0x4A | ||
58 | #define MAX98371_GLOBAL_ENABLE 0x50 | ||
59 | #define MAX98371_SOFT_RESET 0x51 | ||
60 | #define MAX98371_VERSION 0xFF | ||
61 | |||
62 | |||
63 | struct max98371_priv { | ||
64 | struct regmap *regmap; | ||
65 | struct snd_soc_codec *codec; | ||
66 | }; | ||
67 | #endif | ||
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 1c8729984c2b..683769f0f246 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c | |||
@@ -343,9 +343,12 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { | |||
343 | SND_SOC_DAPM_SUPPLY("ADC Power", NAU8825_REG_ANALOG_ADC_2, 6, 0, NULL, | 343 | SND_SOC_DAPM_SUPPLY("ADC Power", NAU8825_REG_ANALOG_ADC_2, 6, 0, NULL, |
344 | 0), | 344 | 0), |
345 | 345 | ||
346 | /* ADC for button press detection */ | 346 | /* ADC for button press detection. A dapm supply widget is used to |
347 | SND_SOC_DAPM_ADC("SAR", NULL, NAU8825_REG_SAR_CTRL, | 347 | * prevent dapm_power_widgets keeping the codec at SND_SOC_BIAS_ON |
348 | NAU8825_SAR_ADC_EN_SFT, 0), | 348 | * during suspend. |
349 | */ | ||
350 | SND_SOC_DAPM_SUPPLY("SAR", NAU8825_REG_SAR_CTRL, | ||
351 | NAU8825_SAR_ADC_EN_SFT, 0, NULL, 0), | ||
349 | 352 | ||
350 | SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0), | 353 | SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0), |
351 | SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0), | 354 | SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0), |
@@ -607,6 +610,16 @@ static bool nau8825_is_jack_inserted(struct regmap *regmap) | |||
607 | 610 | ||
608 | static void nau8825_restart_jack_detection(struct regmap *regmap) | 611 | static void nau8825_restart_jack_detection(struct regmap *regmap) |
609 | { | 612 | { |
613 | /* Chip needs one FSCLK cycle in order to generate interrupts, | ||
614 | * as we cannot guarantee one will be provided by the system. Turning | ||
615 | * master mode on then off enables us to generate that FSCLK cycle | ||
616 | * with a minimum of contention on the clock bus. | ||
617 | */ | ||
618 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
619 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_MASTER); | ||
620 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
621 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_SLAVE); | ||
622 | |||
610 | /* this will restart the entire jack detection process including MIC/GND | 623 | /* this will restart the entire jack detection process including MIC/GND |
611 | * switching and create interrupts. We have to go from 0 to 1 and back | 624 | * switching and create interrupts. We have to go from 0 to 1 and back |
612 | * to 0 to restart. | 625 | * to 0 to restart. |
@@ -728,7 +741,10 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) | |||
728 | struct regmap *regmap = nau8825->regmap; | 741 | struct regmap *regmap = nau8825->regmap; |
729 | int active_irq, clear_irq = 0, event = 0, event_mask = 0; | 742 | int active_irq, clear_irq = 0, event = 0, event_mask = 0; |
730 | 743 | ||
731 | regmap_read(regmap, NAU8825_REG_IRQ_STATUS, &active_irq); | 744 | if (regmap_read(regmap, NAU8825_REG_IRQ_STATUS, &active_irq)) { |
745 | dev_err(nau8825->dev, "failed to read irq status\n"); | ||
746 | return IRQ_NONE; | ||
747 | } | ||
732 | 748 | ||
733 | if ((active_irq & NAU8825_JACK_EJECTION_IRQ_MASK) == | 749 | if ((active_irq & NAU8825_JACK_EJECTION_IRQ_MASK) == |
734 | NAU8825_JACK_EJECTION_DETECTED) { | 750 | NAU8825_JACK_EJECTION_DETECTED) { |
@@ -1141,33 +1157,74 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec, | |||
1141 | return ret; | 1157 | return ret; |
1142 | } | 1158 | } |
1143 | } | 1159 | } |
1144 | |||
1145 | ret = regcache_sync(nau8825->regmap); | ||
1146 | if (ret) { | ||
1147 | dev_err(codec->dev, | ||
1148 | "Failed to sync cache: %d\n", ret); | ||
1149 | return ret; | ||
1150 | } | ||
1151 | } | 1160 | } |
1152 | |||
1153 | break; | 1161 | break; |
1154 | 1162 | ||
1155 | case SND_SOC_BIAS_OFF: | 1163 | case SND_SOC_BIAS_OFF: |
1156 | if (nau8825->mclk_freq) | 1164 | if (nau8825->mclk_freq) |
1157 | clk_disable_unprepare(nau8825->mclk); | 1165 | clk_disable_unprepare(nau8825->mclk); |
1158 | |||
1159 | regcache_mark_dirty(nau8825->regmap); | ||
1160 | break; | 1166 | break; |
1161 | } | 1167 | } |
1162 | return 0; | 1168 | return 0; |
1163 | } | 1169 | } |
1164 | 1170 | ||
1171 | #ifdef CONFIG_PM | ||
1172 | static int nau8825_suspend(struct snd_soc_codec *codec) | ||
1173 | { | ||
1174 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); | ||
1175 | |||
1176 | disable_irq(nau8825->irq); | ||
1177 | regcache_cache_only(nau8825->regmap, true); | ||
1178 | regcache_mark_dirty(nau8825->regmap); | ||
1179 | |||
1180 | return 0; | ||
1181 | } | ||
1182 | |||
1183 | static int nau8825_resume(struct snd_soc_codec *codec) | ||
1184 | { | ||
1185 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); | ||
1186 | |||
1187 | /* The chip may lose power and reset in S3. regcache_sync restores | ||
1188 | * register values including configurations for sysclk, irq, and | ||
1189 | * jack/button detection. | ||
1190 | */ | ||
1191 | regcache_cache_only(nau8825->regmap, false); | ||
1192 | regcache_sync(nau8825->regmap); | ||
1193 | |||
1194 | /* Check the jack plug status directly. If the headset is unplugged | ||
1195 | * during S3 when the chip has no power, there will be no jack | ||
1196 | * detection irq even after the nau8825_restart_jack_detection below, | ||
1197 | * because the chip just thinks no headset has ever been plugged in. | ||
1198 | */ | ||
1199 | if (!nau8825_is_jack_inserted(nau8825->regmap)) { | ||
1200 | nau8825_eject_jack(nau8825); | ||
1201 | snd_soc_jack_report(nau8825->jack, 0, SND_JACK_HEADSET); | ||
1202 | } | ||
1203 | |||
1204 | enable_irq(nau8825->irq); | ||
1205 | |||
1206 | /* Run jack detection to check the type (OMTP or CTIA) of the headset | ||
1207 | * if there is one. This handles the case where a different type of | ||
1208 | * headset is plugged in during S3. This triggers an IRQ iff a headset | ||
1209 | * is already plugged in. | ||
1210 | */ | ||
1211 | nau8825_restart_jack_detection(nau8825->regmap); | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||
1215 | #else | ||
1216 | #define nau8825_suspend NULL | ||
1217 | #define nau8825_resume NULL | ||
1218 | #endif | ||
1219 | |||
1165 | static struct snd_soc_codec_driver nau8825_codec_driver = { | 1220 | static struct snd_soc_codec_driver nau8825_codec_driver = { |
1166 | .probe = nau8825_codec_probe, | 1221 | .probe = nau8825_codec_probe, |
1167 | .set_sysclk = nau8825_set_sysclk, | 1222 | .set_sysclk = nau8825_set_sysclk, |
1168 | .set_pll = nau8825_set_pll, | 1223 | .set_pll = nau8825_set_pll, |
1169 | .set_bias_level = nau8825_set_bias_level, | 1224 | .set_bias_level = nau8825_set_bias_level, |
1170 | .suspend_bias_off = true, | 1225 | .suspend_bias_off = true, |
1226 | .suspend = nau8825_suspend, | ||
1227 | .resume = nau8825_resume, | ||
1171 | 1228 | ||
1172 | .controls = nau8825_controls, | 1229 | .controls = nau8825_controls, |
1173 | .num_controls = ARRAY_SIZE(nau8825_controls), | 1230 | .num_controls = ARRAY_SIZE(nau8825_controls), |
@@ -1277,16 +1334,6 @@ static int nau8825_setup_irq(struct nau8825 *nau8825) | |||
1277 | regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL, | 1334 | regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL, |
1278 | NAU8825_ENABLE_DACR, NAU8825_ENABLE_DACR); | 1335 | NAU8825_ENABLE_DACR, NAU8825_ENABLE_DACR); |
1279 | 1336 | ||
1280 | /* Chip needs one FSCLK cycle in order to generate interrupts, | ||
1281 | * as we cannot guarantee one will be provided by the system. Turning | ||
1282 | * master mode on then off enables us to generate that FSCLK cycle | ||
1283 | * with a minimum of contention on the clock bus. | ||
1284 | */ | ||
1285 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
1286 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_MASTER); | ||
1287 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
1288 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_SLAVE); | ||
1289 | |||
1290 | ret = devm_request_threaded_irq(nau8825->dev, nau8825->irq, NULL, | 1337 | ret = devm_request_threaded_irq(nau8825->dev, nau8825->irq, NULL, |
1291 | nau8825_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 1338 | nau8825_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
1292 | "nau8825", nau8825); | 1339 | "nau8825", nau8825); |
@@ -1354,36 +1401,6 @@ static int nau8825_i2c_remove(struct i2c_client *client) | |||
1354 | return 0; | 1401 | return 0; |
1355 | } | 1402 | } |
1356 | 1403 | ||
1357 | #ifdef CONFIG_PM_SLEEP | ||
1358 | static int nau8825_suspend(struct device *dev) | ||
1359 | { | ||
1360 | struct i2c_client *client = to_i2c_client(dev); | ||
1361 | struct nau8825 *nau8825 = dev_get_drvdata(dev); | ||
1362 | |||
1363 | disable_irq(client->irq); | ||
1364 | regcache_cache_only(nau8825->regmap, true); | ||
1365 | regcache_mark_dirty(nau8825->regmap); | ||
1366 | |||
1367 | return 0; | ||
1368 | } | ||
1369 | |||
1370 | static int nau8825_resume(struct device *dev) | ||
1371 | { | ||
1372 | struct i2c_client *client = to_i2c_client(dev); | ||
1373 | struct nau8825 *nau8825 = dev_get_drvdata(dev); | ||
1374 | |||
1375 | regcache_cache_only(nau8825->regmap, false); | ||
1376 | regcache_sync(nau8825->regmap); | ||
1377 | enable_irq(client->irq); | ||
1378 | |||
1379 | return 0; | ||
1380 | } | ||
1381 | #endif | ||
1382 | |||
1383 | static const struct dev_pm_ops nau8825_pm = { | ||
1384 | SET_SYSTEM_SLEEP_PM_OPS(nau8825_suspend, nau8825_resume) | ||
1385 | }; | ||
1386 | |||
1387 | static const struct i2c_device_id nau8825_i2c_ids[] = { | 1404 | static const struct i2c_device_id nau8825_i2c_ids[] = { |
1388 | { "nau8825", 0 }, | 1405 | { "nau8825", 0 }, |
1389 | { } | 1406 | { } |
@@ -1410,7 +1427,6 @@ static struct i2c_driver nau8825_driver = { | |||
1410 | .name = "nau8825", | 1427 | .name = "nau8825", |
1411 | .of_match_table = of_match_ptr(nau8825_of_ids), | 1428 | .of_match_table = of_match_ptr(nau8825_of_ids), |
1412 | .acpi_match_table = ACPI_PTR(nau8825_acpi_match), | 1429 | .acpi_match_table = ACPI_PTR(nau8825_acpi_match), |
1413 | .pm = &nau8825_pm, | ||
1414 | }, | 1430 | }, |
1415 | .probe = nau8825_i2c_probe, | 1431 | .probe = nau8825_i2c_probe, |
1416 | .remove = nau8825_i2c_remove, | 1432 | .remove = nau8825_i2c_remove, |
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c new file mode 100644 index 000000000000..ed515677409b --- /dev/null +++ b/sound/soc/codecs/pcm5102a.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Driver for the PCM5102A codec | ||
3 | * | ||
4 | * Author: Florian Meier <florian.meier@koalo.de> | ||
5 | * Copyright 2013 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | |||
21 | #include <sound/soc.h> | ||
22 | |||
23 | static struct snd_soc_dai_driver pcm5102a_dai = { | ||
24 | .name = "pcm5102a-hifi", | ||
25 | .playback = { | ||
26 | .channels_min = 2, | ||
27 | .channels_max = 2, | ||
28 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
29 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
30 | SNDRV_PCM_FMTBIT_S24_LE | | ||
31 | SNDRV_PCM_FMTBIT_S32_LE | ||
32 | }, | ||
33 | }; | ||
34 | |||
35 | static struct snd_soc_codec_driver soc_codec_dev_pcm5102a; | ||
36 | |||
37 | static int pcm5102a_probe(struct platform_device *pdev) | ||
38 | { | ||
39 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a, | ||
40 | &pcm5102a_dai, 1); | ||
41 | } | ||
42 | |||
43 | static int pcm5102a_remove(struct platform_device *pdev) | ||
44 | { | ||
45 | snd_soc_unregister_codec(&pdev->dev); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static const struct of_device_id pcm5102a_of_match[] = { | ||
50 | { .compatible = "ti,pcm5102a", }, | ||
51 | { } | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(of, pcm5102a_of_match); | ||
54 | |||
55 | static struct platform_driver pcm5102a_codec_driver = { | ||
56 | .probe = pcm5102a_probe, | ||
57 | .remove = pcm5102a_remove, | ||
58 | .driver = { | ||
59 | .name = "pcm5102a-codec", | ||
60 | .owner = THIS_MODULE, | ||
61 | .of_match_table = pcm5102a_of_match, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | module_platform_driver(pcm5102a_codec_driver); | ||
66 | |||
67 | MODULE_DESCRIPTION("ASoC PCM5102A codec driver"); | ||
68 | MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>"); | ||
69 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index f0e6c06e89ac..f80cfe4d2ef2 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/dmi.h> | ||
20 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -275,6 +276,8 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) | |||
275 | } else { | 276 | } else { |
276 | *mic = false; | 277 | *mic = false; |
277 | regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20); | 278 | regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20); |
279 | regmap_update_bits(rt298->regmap, | ||
280 | RT298_CBJ_CTRL1, 0x0400, 0x0000); | ||
278 | } | 281 | } |
279 | } else { | 282 | } else { |
280 | regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); | 283 | regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); |
@@ -481,6 +484,26 @@ static int rt298_adc_event(struct snd_soc_dapm_widget *w, | |||
481 | snd_soc_update_bits(codec, | 484 | snd_soc_update_bits(codec, |
482 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), | 485 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), |
483 | 0x7080, 0x7000); | 486 | 0x7080, 0x7000); |
487 | /* If MCLK doesn't exist, reset AD filter */ | ||
488 | if (!(snd_soc_read(codec, RT298_VAD_CTRL) & 0x200)) { | ||
489 | pr_info("NO MCLK\n"); | ||
490 | switch (nid) { | ||
491 | case RT298_ADC_IN1: | ||
492 | snd_soc_update_bits(codec, | ||
493 | RT298_D_FILTER_CTRL, 0x2, 0x2); | ||
494 | mdelay(10); | ||
495 | snd_soc_update_bits(codec, | ||
496 | RT298_D_FILTER_CTRL, 0x2, 0x0); | ||
497 | break; | ||
498 | case RT298_ADC_IN2: | ||
499 | snd_soc_update_bits(codec, | ||
500 | RT298_D_FILTER_CTRL, 0x4, 0x4); | ||
501 | mdelay(10); | ||
502 | snd_soc_update_bits(codec, | ||
503 | RT298_D_FILTER_CTRL, 0x4, 0x0); | ||
504 | break; | ||
505 | } | ||
506 | } | ||
484 | break; | 507 | break; |
485 | case SND_SOC_DAPM_PRE_PMD: | 508 | case SND_SOC_DAPM_PRE_PMD: |
486 | snd_soc_update_bits(codec, | 509 | snd_soc_update_bits(codec, |
@@ -519,30 +542,12 @@ static int rt298_mic1_event(struct snd_soc_dapm_widget *w, | |||
519 | return 0; | 542 | return 0; |
520 | } | 543 | } |
521 | 544 | ||
522 | static int rt298_vref_event(struct snd_soc_dapm_widget *w, | ||
523 | struct snd_kcontrol *kcontrol, int event) | ||
524 | { | ||
525 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
526 | |||
527 | switch (event) { | ||
528 | case SND_SOC_DAPM_PRE_PMU: | ||
529 | snd_soc_update_bits(codec, | ||
530 | RT298_CBJ_CTRL1, 0x0400, 0x0000); | ||
531 | mdelay(50); | ||
532 | break; | ||
533 | default: | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = { | 545 | static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = { |
541 | 546 | ||
542 | SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1, | 547 | SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1, |
543 | 12, 1, NULL, 0), | 548 | 12, 1, NULL, 0), |
544 | SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1, | 549 | SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1, |
545 | 0, 1, rt298_vref_event, SND_SOC_DAPM_PRE_PMU), | 550 | 0, 1, NULL, 0), |
546 | SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2, | 551 | SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2, |
547 | 1, 0, NULL, 0), | 552 | 1, 0, NULL, 0), |
548 | SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2, | 553 | SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2, |
@@ -933,18 +938,9 @@ static int rt298_set_bias_level(struct snd_soc_codec *codec, | |||
933 | } | 938 | } |
934 | break; | 939 | break; |
935 | 940 | ||
936 | case SND_SOC_BIAS_ON: | ||
937 | mdelay(30); | ||
938 | snd_soc_update_bits(codec, | ||
939 | RT298_CBJ_CTRL1, 0x0400, 0x0400); | ||
940 | |||
941 | break; | ||
942 | |||
943 | case SND_SOC_BIAS_STANDBY: | 941 | case SND_SOC_BIAS_STANDBY: |
944 | snd_soc_write(codec, | 942 | snd_soc_write(codec, |
945 | RT298_SET_AUDIO_POWER, AC_PWRST_D3); | 943 | RT298_SET_AUDIO_POWER, AC_PWRST_D3); |
946 | snd_soc_update_bits(codec, | ||
947 | RT298_CBJ_CTRL1, 0x0400, 0x0000); | ||
948 | break; | 944 | break; |
949 | 945 | ||
950 | default: | 946 | default: |
@@ -1132,6 +1128,17 @@ static const struct acpi_device_id rt298_acpi_match[] = { | |||
1132 | }; | 1128 | }; |
1133 | MODULE_DEVICE_TABLE(acpi, rt298_acpi_match); | 1129 | MODULE_DEVICE_TABLE(acpi, rt298_acpi_match); |
1134 | 1130 | ||
1131 | static const struct dmi_system_id force_combo_jack_table[] = { | ||
1132 | { | ||
1133 | .ident = "Intel Broxton P", | ||
1134 | .matches = { | ||
1135 | DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp"), | ||
1136 | DMI_MATCH(DMI_PRODUCT_NAME, "Broxton P") | ||
1137 | } | ||
1138 | }, | ||
1139 | { } | ||
1140 | }; | ||
1141 | |||
1135 | static int rt298_i2c_probe(struct i2c_client *i2c, | 1142 | static int rt298_i2c_probe(struct i2c_client *i2c, |
1136 | const struct i2c_device_id *id) | 1143 | const struct i2c_device_id *id) |
1137 | { | 1144 | { |
@@ -1184,11 +1191,16 @@ static int rt298_i2c_probe(struct i2c_client *i2c, | |||
1184 | 1191 | ||
1185 | /* enable jack combo mode on supported devices */ | 1192 | /* enable jack combo mode on supported devices */ |
1186 | acpiid = acpi_match_device(dev->driver->acpi_match_table, dev); | 1193 | acpiid = acpi_match_device(dev->driver->acpi_match_table, dev); |
1187 | if (acpiid) { | 1194 | if (acpiid && acpiid->driver_data) { |
1188 | rt298->pdata = *(struct rt298_platform_data *) | 1195 | rt298->pdata = *(struct rt298_platform_data *) |
1189 | acpiid->driver_data; | 1196 | acpiid->driver_data; |
1190 | } | 1197 | } |
1191 | 1198 | ||
1199 | if (dmi_check_system(force_combo_jack_table)) { | ||
1200 | rt298->pdata.cbj_en = true; | ||
1201 | rt298->pdata.gpio2_en = false; | ||
1202 | } | ||
1203 | |||
1192 | /* VREF Charging */ | 1204 | /* VREF Charging */ |
1193 | regmap_update_bits(rt298->regmap, 0x04, 0x80, 0x80); | 1205 | regmap_update_bits(rt298->regmap, 0x04, 0x80, 0x80); |
1194 | regmap_update_bits(rt298->regmap, 0x1b, 0x860, 0x860); | 1206 | regmap_update_bits(rt298->regmap, 0x1b, 0x860, 0x860); |
diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h index d66f8847b676..3638f3d61209 100644 --- a/sound/soc/codecs/rt298.h +++ b/sound/soc/codecs/rt298.h | |||
@@ -137,6 +137,7 @@ | |||
137 | #define RT298_A_BIAS_CTRL2 0x02 | 137 | #define RT298_A_BIAS_CTRL2 0x02 |
138 | #define RT298_POWER_CTRL1 0x03 | 138 | #define RT298_POWER_CTRL1 0x03 |
139 | #define RT298_A_BIAS_CTRL3 0x04 | 139 | #define RT298_A_BIAS_CTRL3 0x04 |
140 | #define RT298_D_FILTER_CTRL 0x05 | ||
140 | #define RT298_POWER_CTRL2 0x08 | 141 | #define RT298_POWER_CTRL2 0x08 |
141 | #define RT298_I2S_CTRL1 0x09 | 142 | #define RT298_I2S_CTRL1 0x09 |
142 | #define RT298_I2S_CTRL2 0x0a | 143 | #define RT298_I2S_CTRL2 0x0a |
@@ -148,6 +149,7 @@ | |||
148 | #define RT298_IRQ_CTRL 0x33 | 149 | #define RT298_IRQ_CTRL 0x33 |
149 | #define RT298_WIND_FILTER_CTRL 0x46 | 150 | #define RT298_WIND_FILTER_CTRL 0x46 |
150 | #define RT298_PLL_CTRL1 0x49 | 151 | #define RT298_PLL_CTRL1 0x49 |
152 | #define RT298_VAD_CTRL 0x4e | ||
151 | #define RT298_CBJ_CTRL1 0x4f | 153 | #define RT298_CBJ_CTRL1 0x4f |
152 | #define RT298_CBJ_CTRL2 0x50 | 154 | #define RT298_CBJ_CTRL2 0x50 |
153 | #define RT298_PLL_CTRL 0x63 | 155 | #define RT298_PLL_CTRL 0x63 |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index e8b5ba04417a..09e8988bbb2d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -359,7 +359,7 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv, | |||
359 | 359 | ||
360 | /* Interface data select */ | 360 | /* Interface data select */ |
361 | static const char * const rt5640_data_select[] = { | 361 | static const char * const rt5640_data_select[] = { |
362 | "Normal", "left copy to right", "right copy to left", "Swap"}; | 362 | "Normal", "Swap", "left copy to right", "right copy to left"}; |
363 | 363 | ||
364 | static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, | 364 | static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, |
365 | RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); | 365 | RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); |
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 1761c3a98b76..58b664b06c16 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h | |||
@@ -443,39 +443,39 @@ | |||
443 | #define RT5640_IF1_DAC_SEL_MASK (0x3 << 14) | 443 | #define RT5640_IF1_DAC_SEL_MASK (0x3 << 14) |
444 | #define RT5640_IF1_DAC_SEL_SFT 14 | 444 | #define RT5640_IF1_DAC_SEL_SFT 14 |
445 | #define RT5640_IF1_DAC_SEL_NOR (0x0 << 14) | 445 | #define RT5640_IF1_DAC_SEL_NOR (0x0 << 14) |
446 | #define RT5640_IF1_DAC_SEL_L2R (0x1 << 14) | 446 | #define RT5640_IF1_DAC_SEL_SWAP (0x1 << 14) |
447 | #define RT5640_IF1_DAC_SEL_R2L (0x2 << 14) | 447 | #define RT5640_IF1_DAC_SEL_L2R (0x2 << 14) |
448 | #define RT5640_IF1_DAC_SEL_SWAP (0x3 << 14) | 448 | #define RT5640_IF1_DAC_SEL_R2L (0x3 << 14) |
449 | #define RT5640_IF1_ADC_SEL_MASK (0x3 << 12) | 449 | #define RT5640_IF1_ADC_SEL_MASK (0x3 << 12) |
450 | #define RT5640_IF1_ADC_SEL_SFT 12 | 450 | #define RT5640_IF1_ADC_SEL_SFT 12 |
451 | #define RT5640_IF1_ADC_SEL_NOR (0x0 << 12) | 451 | #define RT5640_IF1_ADC_SEL_NOR (0x0 << 12) |
452 | #define RT5640_IF1_ADC_SEL_L2R (0x1 << 12) | 452 | #define RT5640_IF1_ADC_SEL_SWAP (0x1 << 12) |
453 | #define RT5640_IF1_ADC_SEL_R2L (0x2 << 12) | 453 | #define RT5640_IF1_ADC_SEL_L2R (0x2 << 12) |
454 | #define RT5640_IF1_ADC_SEL_SWAP (0x3 << 12) | 454 | #define RT5640_IF1_ADC_SEL_R2L (0x3 << 12) |
455 | #define RT5640_IF2_DAC_SEL_MASK (0x3 << 10) | 455 | #define RT5640_IF2_DAC_SEL_MASK (0x3 << 10) |
456 | #define RT5640_IF2_DAC_SEL_SFT 10 | 456 | #define RT5640_IF2_DAC_SEL_SFT 10 |
457 | #define RT5640_IF2_DAC_SEL_NOR (0x0 << 10) | 457 | #define RT5640_IF2_DAC_SEL_NOR (0x0 << 10) |
458 | #define RT5640_IF2_DAC_SEL_L2R (0x1 << 10) | 458 | #define RT5640_IF2_DAC_SEL_SWAP (0x1 << 10) |
459 | #define RT5640_IF2_DAC_SEL_R2L (0x2 << 10) | 459 | #define RT5640_IF2_DAC_SEL_L2R (0x2 << 10) |
460 | #define RT5640_IF2_DAC_SEL_SWAP (0x3 << 10) | 460 | #define RT5640_IF2_DAC_SEL_R2L (0x3 << 10) |
461 | #define RT5640_IF2_ADC_SEL_MASK (0x3 << 8) | 461 | #define RT5640_IF2_ADC_SEL_MASK (0x3 << 8) |
462 | #define RT5640_IF2_ADC_SEL_SFT 8 | 462 | #define RT5640_IF2_ADC_SEL_SFT 8 |
463 | #define RT5640_IF2_ADC_SEL_NOR (0x0 << 8) | 463 | #define RT5640_IF2_ADC_SEL_NOR (0x0 << 8) |
464 | #define RT5640_IF2_ADC_SEL_L2R (0x1 << 8) | 464 | #define RT5640_IF2_ADC_SEL_SWAP (0x1 << 8) |
465 | #define RT5640_IF2_ADC_SEL_R2L (0x2 << 8) | 465 | #define RT5640_IF2_ADC_SEL_L2R (0x2 << 8) |
466 | #define RT5640_IF2_ADC_SEL_SWAP (0x3 << 8) | 466 | #define RT5640_IF2_ADC_SEL_R2L (0x3 << 8) |
467 | #define RT5640_IF3_DAC_SEL_MASK (0x3 << 6) | 467 | #define RT5640_IF3_DAC_SEL_MASK (0x3 << 6) |
468 | #define RT5640_IF3_DAC_SEL_SFT 6 | 468 | #define RT5640_IF3_DAC_SEL_SFT 6 |
469 | #define RT5640_IF3_DAC_SEL_NOR (0x0 << 6) | 469 | #define RT5640_IF3_DAC_SEL_NOR (0x0 << 6) |
470 | #define RT5640_IF3_DAC_SEL_L2R (0x1 << 6) | 470 | #define RT5640_IF3_DAC_SEL_SWAP (0x1 << 6) |
471 | #define RT5640_IF3_DAC_SEL_R2L (0x2 << 6) | 471 | #define RT5640_IF3_DAC_SEL_L2R (0x2 << 6) |
472 | #define RT5640_IF3_DAC_SEL_SWAP (0x3 << 6) | 472 | #define RT5640_IF3_DAC_SEL_R2L (0x3 << 6) |
473 | #define RT5640_IF3_ADC_SEL_MASK (0x3 << 4) | 473 | #define RT5640_IF3_ADC_SEL_MASK (0x3 << 4) |
474 | #define RT5640_IF3_ADC_SEL_SFT 4 | 474 | #define RT5640_IF3_ADC_SEL_SFT 4 |
475 | #define RT5640_IF3_ADC_SEL_NOR (0x0 << 4) | 475 | #define RT5640_IF3_ADC_SEL_NOR (0x0 << 4) |
476 | #define RT5640_IF3_ADC_SEL_L2R (0x1 << 4) | 476 | #define RT5640_IF3_ADC_SEL_SWAP (0x1 << 4) |
477 | #define RT5640_IF3_ADC_SEL_R2L (0x2 << 4) | 477 | #define RT5640_IF3_ADC_SEL_L2R (0x2 << 4) |
478 | #define RT5640_IF3_ADC_SEL_SWAP (0x3 << 4) | 478 | #define RT5640_IF3_ADC_SEL_R2L (0x3 << 4) |
479 | 479 | ||
480 | /* REC Left Mixer Control 1 (0x3b) */ | 480 | /* REC Left Mixer Control 1 (0x3b) */ |
481 | #define RT5640_G_HP_L_RM_L_MASK (0x7 << 13) | 481 | #define RT5640_G_HP_L_RM_L_MASK (0x7 << 13) |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 7af5e7380d61..3c6594da6c9c 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -3286,10 +3286,8 @@ static void rt5645_jack_detect_work(struct work_struct *work) | |||
3286 | if (btn_type == 0)/* button release */ | 3286 | if (btn_type == 0)/* button release */ |
3287 | report = rt5645->jack_type; | 3287 | report = rt5645->jack_type; |
3288 | else { | 3288 | else { |
3289 | if (rt5645->pdata.jd_invert) { | 3289 | mod_timer(&rt5645->btn_check_timer, |
3290 | mod_timer(&rt5645->btn_check_timer, | 3290 | msecs_to_jiffies(100)); |
3291 | msecs_to_jiffies(100)); | ||
3292 | } | ||
3293 | } | 3291 | } |
3294 | 3292 | ||
3295 | break; | 3293 | break; |
@@ -3557,6 +3555,12 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { | |||
3557 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), | 3555 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), |
3558 | }, | 3556 | }, |
3559 | }, | 3557 | }, |
3558 | { | ||
3559 | .ident = "Google Setzer", | ||
3560 | .matches = { | ||
3561 | DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"), | ||
3562 | }, | ||
3563 | }, | ||
3560 | { } | 3564 | { } |
3561 | }; | 3565 | }; |
3562 | 3566 | ||
@@ -3810,9 +3814,9 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
3810 | if (rt5645->pdata.jd_invert) { | 3814 | if (rt5645->pdata.jd_invert) { |
3811 | regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, | 3815 | regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, |
3812 | RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); | 3816 | RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); |
3813 | setup_timer(&rt5645->btn_check_timer, | ||
3814 | rt5645_btn_check_callback, (unsigned long)rt5645); | ||
3815 | } | 3817 | } |
3818 | setup_timer(&rt5645->btn_check_timer, | ||
3819 | rt5645_btn_check_callback, (unsigned long)rt5645); | ||
3816 | 3820 | ||
3817 | INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); | 3821 | INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); |
3818 | INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work); | 3822 | INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work); |
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 39307ad41a34..b8d19b77bde9 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c | |||
@@ -4,6 +4,9 @@ | |||
4 | * Copyright (C) 2015 Google, Inc. | 4 | * Copyright (C) 2015 Google, Inc. |
5 | * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> | 5 | * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> |
6 | * | 6 | * |
7 | * TAS5721 support: | ||
8 | * Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com> | ||
9 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
@@ -57,6 +60,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) | |||
57 | case TAS571X_CH1_VOL_REG: | 60 | case TAS571X_CH1_VOL_REG: |
58 | case TAS571X_CH2_VOL_REG: | 61 | case TAS571X_CH2_VOL_REG: |
59 | return priv->chip->vol_reg_size; | 62 | return priv->chip->vol_reg_size; |
63 | case TAS571X_INPUT_MUX_REG: | ||
64 | case TAS571X_CH4_SRC_SELECT_REG: | ||
65 | case TAS571X_PWM_MUX_REG: | ||
66 | return 4; | ||
60 | default: | 67 | default: |
61 | return 1; | 68 | return 1; |
62 | } | 69 | } |
@@ -167,6 +174,23 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream, | |||
167 | TAS571X_SDI_FMT_MASK, val); | 174 | TAS571X_SDI_FMT_MASK, val); |
168 | } | 175 | } |
169 | 176 | ||
177 | static int tas571x_mute(struct snd_soc_dai *dai, int mute) | ||
178 | { | ||
179 | struct snd_soc_codec *codec = dai->codec; | ||
180 | u8 sysctl2; | ||
181 | int ret; | ||
182 | |||
183 | sysctl2 = mute ? TAS571X_SYS_CTRL_2_SDN_MASK : 0; | ||
184 | |||
185 | ret = snd_soc_update_bits(codec, | ||
186 | TAS571X_SYS_CTRL_2_REG, | ||
187 | TAS571X_SYS_CTRL_2_SDN_MASK, | ||
188 | sysctl2); | ||
189 | usleep_range(1000, 2000); | ||
190 | |||
191 | return ret; | ||
192 | } | ||
193 | |||
170 | static int tas571x_set_bias_level(struct snd_soc_codec *codec, | 194 | static int tas571x_set_bias_level(struct snd_soc_codec *codec, |
171 | enum snd_soc_bias_level level) | 195 | enum snd_soc_bias_level level) |
172 | { | 196 | { |
@@ -214,6 +238,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec, | |||
214 | static const struct snd_soc_dai_ops tas571x_dai_ops = { | 238 | static const struct snd_soc_dai_ops tas571x_dai_ops = { |
215 | .set_fmt = tas571x_set_dai_fmt, | 239 | .set_fmt = tas571x_set_dai_fmt, |
216 | .hw_params = tas571x_hw_params, | 240 | .hw_params = tas571x_hw_params, |
241 | .digital_mute = tas571x_mute, | ||
217 | }; | 242 | }; |
218 | 243 | ||
219 | static const char *const tas5711_supply_names[] = { | 244 | static const char *const tas5711_supply_names[] = { |
@@ -241,6 +266,26 @@ static const struct snd_kcontrol_new tas5711_controls[] = { | |||
241 | 1, 1), | 266 | 1, 1), |
242 | }; | 267 | }; |
243 | 268 | ||
269 | static const struct regmap_range tas571x_readonly_regs_range[] = { | ||
270 | regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_DEV_ID_REG), | ||
271 | }; | ||
272 | |||
273 | static const struct regmap_range tas571x_volatile_regs_range[] = { | ||
274 | regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_ERR_STATUS_REG), | ||
275 | regmap_reg_range(TAS571X_OSC_TRIM_REG, TAS571X_OSC_TRIM_REG), | ||
276 | }; | ||
277 | |||
278 | static const struct regmap_access_table tas571x_write_regs = { | ||
279 | .no_ranges = tas571x_readonly_regs_range, | ||
280 | .n_no_ranges = ARRAY_SIZE(tas571x_readonly_regs_range), | ||
281 | }; | ||
282 | |||
283 | static const struct regmap_access_table tas571x_volatile_regs = { | ||
284 | .yes_ranges = tas571x_volatile_regs_range, | ||
285 | .n_yes_ranges = ARRAY_SIZE(tas571x_volatile_regs_range), | ||
286 | |||
287 | }; | ||
288 | |||
244 | static const struct reg_default tas5711_reg_defaults[] = { | 289 | static const struct reg_default tas5711_reg_defaults[] = { |
245 | { 0x04, 0x05 }, | 290 | { 0x04, 0x05 }, |
246 | { 0x05, 0x40 }, | 291 | { 0x05, 0x40 }, |
@@ -260,6 +305,8 @@ static const struct regmap_config tas5711_regmap_config = { | |||
260 | .reg_defaults = tas5711_reg_defaults, | 305 | .reg_defaults = tas5711_reg_defaults, |
261 | .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults), | 306 | .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults), |
262 | .cache_type = REGCACHE_RBTREE, | 307 | .cache_type = REGCACHE_RBTREE, |
308 | .wr_table = &tas571x_write_regs, | ||
309 | .volatile_table = &tas571x_volatile_regs, | ||
263 | }; | 310 | }; |
264 | 311 | ||
265 | static const struct tas571x_chip tas5711_chip = { | 312 | static const struct tas571x_chip tas5711_chip = { |
@@ -314,6 +361,8 @@ static const struct regmap_config tas5717_regmap_config = { | |||
314 | .reg_defaults = tas5717_reg_defaults, | 361 | .reg_defaults = tas5717_reg_defaults, |
315 | .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults), | 362 | .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults), |
316 | .cache_type = REGCACHE_RBTREE, | 363 | .cache_type = REGCACHE_RBTREE, |
364 | .wr_table = &tas571x_write_regs, | ||
365 | .volatile_table = &tas571x_volatile_regs, | ||
317 | }; | 366 | }; |
318 | 367 | ||
319 | /* This entry is reused for tas5719 as the software interface is identical. */ | 368 | /* This entry is reused for tas5719 as the software interface is identical. */ |
@@ -326,6 +375,77 @@ static const struct tas571x_chip tas5717_chip = { | |||
326 | .vol_reg_size = 2, | 375 | .vol_reg_size = 2, |
327 | }; | 376 | }; |
328 | 377 | ||
378 | static const char *const tas5721_supply_names[] = { | ||
379 | "AVDD", | ||
380 | "DVDD", | ||
381 | "DRVDD", | ||
382 | "PVDD", | ||
383 | }; | ||
384 | |||
385 | static const struct snd_kcontrol_new tas5721_controls[] = { | ||
386 | SOC_SINGLE_TLV("Master Volume", | ||
387 | TAS571X_MVOL_REG, | ||
388 | 0, 0xff, 1, tas5711_volume_tlv), | ||
389 | SOC_DOUBLE_R_TLV("Speaker Volume", | ||
390 | TAS571X_CH1_VOL_REG, | ||
391 | TAS571X_CH2_VOL_REG, | ||
392 | 0, 0xff, 1, tas5711_volume_tlv), | ||
393 | SOC_DOUBLE("Speaker Switch", | ||
394 | TAS571X_SOFT_MUTE_REG, | ||
395 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, | ||
396 | 1, 1), | ||
397 | }; | ||
398 | |||
399 | static const struct reg_default tas5721_reg_defaults[] = { | ||
400 | {TAS571X_CLK_CTRL_REG, 0x6c}, | ||
401 | {TAS571X_DEV_ID_REG, 0x00}, | ||
402 | {TAS571X_ERR_STATUS_REG, 0x00}, | ||
403 | {TAS571X_SYS_CTRL_1_REG, 0xa0}, | ||
404 | {TAS571X_SDI_REG, 0x05}, | ||
405 | {TAS571X_SYS_CTRL_2_REG, 0x40}, | ||
406 | {TAS571X_SOFT_MUTE_REG, 0x00}, | ||
407 | {TAS571X_MVOL_REG, 0xff}, | ||
408 | {TAS571X_CH1_VOL_REG, 0x30}, | ||
409 | {TAS571X_CH2_VOL_REG, 0x30}, | ||
410 | {TAS571X_CH3_VOL_REG, 0x30}, | ||
411 | {TAS571X_VOL_CFG_REG, 0x91}, | ||
412 | {TAS571X_MODULATION_LIMIT_REG, 0x02}, | ||
413 | {TAS571X_IC_DELAY_CH1_REG, 0xac}, | ||
414 | {TAS571X_IC_DELAY_CH2_REG, 0x54}, | ||
415 | {TAS571X_IC_DELAY_CH3_REG, 0xac}, | ||
416 | {TAS571X_IC_DELAY_CH4_REG, 0x54}, | ||
417 | {TAS571X_PWM_CH_SDN_GROUP_REG, 0x30}, | ||
418 | {TAS571X_START_STOP_PERIOD_REG, 0x0f}, | ||
419 | {TAS571X_OSC_TRIM_REG, 0x82}, | ||
420 | {TAS571X_BKND_ERR_REG, 0x02}, | ||
421 | {TAS571X_INPUT_MUX_REG, 0x17772}, | ||
422 | {TAS571X_CH4_SRC_SELECT_REG, 0x4303}, | ||
423 | {TAS571X_PWM_MUX_REG, 0x1021345}, | ||
424 | }; | ||
425 | |||
426 | static const struct regmap_config tas5721_regmap_config = { | ||
427 | .reg_bits = 8, | ||
428 | .val_bits = 32, | ||
429 | .max_register = 0xff, | ||
430 | .reg_read = tas571x_reg_read, | ||
431 | .reg_write = tas571x_reg_write, | ||
432 | .reg_defaults = tas5721_reg_defaults, | ||
433 | .num_reg_defaults = ARRAY_SIZE(tas5721_reg_defaults), | ||
434 | .cache_type = REGCACHE_RBTREE, | ||
435 | .wr_table = &tas571x_write_regs, | ||
436 | .volatile_table = &tas571x_volatile_regs, | ||
437 | }; | ||
438 | |||
439 | |||
440 | static const struct tas571x_chip tas5721_chip = { | ||
441 | .supply_names = tas5721_supply_names, | ||
442 | .num_supply_names = ARRAY_SIZE(tas5721_supply_names), | ||
443 | .controls = tas5711_controls, | ||
444 | .num_controls = ARRAY_SIZE(tas5711_controls), | ||
445 | .regmap_config = &tas5721_regmap_config, | ||
446 | .vol_reg_size = 1, | ||
447 | }; | ||
448 | |||
329 | static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = { | 449 | static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = { |
330 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), | 450 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), |
331 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), | 451 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), |
@@ -386,11 +506,10 @@ static int tas571x_i2c_probe(struct i2c_client *client, | |||
386 | i2c_set_clientdata(client, priv); | 506 | i2c_set_clientdata(client, priv); |
387 | 507 | ||
388 | of_id = of_match_device(tas571x_of_match, dev); | 508 | of_id = of_match_device(tas571x_of_match, dev); |
389 | if (!of_id) { | 509 | if (of_id) |
390 | dev_err(dev, "Unknown device type\n"); | 510 | priv->chip = of_id->data; |
391 | return -EINVAL; | 511 | else |
392 | } | 512 | priv->chip = (void *) id->driver_data; |
393 | priv->chip = of_id->data; | ||
394 | 513 | ||
395 | priv->mclk = devm_clk_get(dev, "mclk"); | 514 | priv->mclk = devm_clk_get(dev, "mclk"); |
396 | if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { | 515 | if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { |
@@ -445,10 +564,6 @@ static int tas571x_i2c_probe(struct i2c_client *client, | |||
445 | if (ret) | 564 | if (ret) |
446 | return ret; | 565 | return ret; |
447 | 566 | ||
448 | ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG, | ||
449 | TAS571X_SYS_CTRL_2_SDN_MASK, 0); | ||
450 | if (ret) | ||
451 | return ret; | ||
452 | 567 | ||
453 | memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); | 568 | memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); |
454 | priv->codec_driver.controls = priv->chip->controls; | 569 | priv->codec_driver.controls = priv->chip->controls; |
@@ -486,14 +601,16 @@ static const struct of_device_id tas571x_of_match[] = { | |||
486 | { .compatible = "ti,tas5711", .data = &tas5711_chip, }, | 601 | { .compatible = "ti,tas5711", .data = &tas5711_chip, }, |
487 | { .compatible = "ti,tas5717", .data = &tas5717_chip, }, | 602 | { .compatible = "ti,tas5717", .data = &tas5717_chip, }, |
488 | { .compatible = "ti,tas5719", .data = &tas5717_chip, }, | 603 | { .compatible = "ti,tas5719", .data = &tas5717_chip, }, |
604 | { .compatible = "ti,tas5721", .data = &tas5721_chip, }, | ||
489 | { } | 605 | { } |
490 | }; | 606 | }; |
491 | MODULE_DEVICE_TABLE(of, tas571x_of_match); | 607 | MODULE_DEVICE_TABLE(of, tas571x_of_match); |
492 | 608 | ||
493 | static const struct i2c_device_id tas571x_i2c_id[] = { | 609 | static const struct i2c_device_id tas571x_i2c_id[] = { |
494 | { "tas5711", 0 }, | 610 | { "tas5711", (kernel_ulong_t) &tas5711_chip }, |
495 | { "tas5717", 0 }, | 611 | { "tas5717", (kernel_ulong_t) &tas5717_chip }, |
496 | { "tas5719", 0 }, | 612 | { "tas5719", (kernel_ulong_t) &tas5717_chip }, |
613 | { "tas5721", (kernel_ulong_t) &tas5721_chip }, | ||
497 | { } | 614 | { } |
498 | }; | 615 | }; |
499 | MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); | 616 | MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); |
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h index 0aee471232cd..cf800c364f0f 100644 --- a/sound/soc/codecs/tas571x.h +++ b/sound/soc/codecs/tas571x.h | |||
@@ -13,6 +13,10 @@ | |||
13 | #define _TAS571X_H | 13 | #define _TAS571X_H |
14 | 14 | ||
15 | /* device registers */ | 15 | /* device registers */ |
16 | #define TAS571X_CLK_CTRL_REG 0x00 | ||
17 | #define TAS571X_DEV_ID_REG 0x01 | ||
18 | #define TAS571X_ERR_STATUS_REG 0x02 | ||
19 | #define TAS571X_SYS_CTRL_1_REG 0x03 | ||
16 | #define TAS571X_SDI_REG 0x04 | 20 | #define TAS571X_SDI_REG 0x04 |
17 | #define TAS571X_SDI_FMT_MASK 0x0f | 21 | #define TAS571X_SDI_FMT_MASK 0x0f |
18 | 22 | ||
@@ -27,7 +31,25 @@ | |||
27 | #define TAS571X_MVOL_REG 0x07 | 31 | #define TAS571X_MVOL_REG 0x07 |
28 | #define TAS571X_CH1_VOL_REG 0x08 | 32 | #define TAS571X_CH1_VOL_REG 0x08 |
29 | #define TAS571X_CH2_VOL_REG 0x09 | 33 | #define TAS571X_CH2_VOL_REG 0x09 |
34 | #define TAS571X_CH3_VOL_REG 0x0a | ||
35 | #define TAS571X_VOL_CFG_REG 0x0e | ||
36 | #define TAS571X_MODULATION_LIMIT_REG 0x10 | ||
37 | #define TAS571X_IC_DELAY_CH1_REG 0x11 | ||
38 | #define TAS571X_IC_DELAY_CH2_REG 0x12 | ||
39 | #define TAS571X_IC_DELAY_CH3_REG 0x13 | ||
40 | #define TAS571X_IC_DELAY_CH4_REG 0x14 | ||
30 | 41 | ||
42 | #define TAS571X_PWM_CH_SDN_GROUP_REG 0x19 /* N/A on TAS5717, TAS5719 */ | ||
43 | #define TAS571X_PWM_CH1_SDN_MASK (1<<0) | ||
44 | #define TAS571X_PWM_CH2_SDN_SHIFT (1<<1) | ||
45 | #define TAS571X_PWM_CH3_SDN_SHIFT (1<<2) | ||
46 | #define TAS571X_PWM_CH4_SDN_SHIFT (1<<3) | ||
47 | |||
48 | #define TAS571X_START_STOP_PERIOD_REG 0x1a | ||
31 | #define TAS571X_OSC_TRIM_REG 0x1b | 49 | #define TAS571X_OSC_TRIM_REG 0x1b |
50 | #define TAS571X_BKND_ERR_REG 0x1c | ||
51 | #define TAS571X_INPUT_MUX_REG 0x20 | ||
52 | #define TAS571X_CH4_SRC_SELECT_REG 0x21 | ||
53 | #define TAS571X_PWM_MUX_REG 0x25 | ||
32 | 54 | ||
33 | #endif /* _TAS571X_H */ | 55 | #endif /* _TAS571X_H */ |
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c new file mode 100644 index 000000000000..f54fb46b77c2 --- /dev/null +++ b/sound/soc/codecs/tas5720.c | |||
@@ -0,0 +1,620 @@ | |||
1 | /* | ||
2 | * tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier | ||
3 | * | ||
4 | * Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Author: Andreas Dannenberg <dannenberg@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | #include <linux/delay.h> | ||
27 | |||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/tlv.h> | ||
33 | |||
34 | #include "tas5720.h" | ||
35 | |||
36 | /* Define how often to check (and clear) the fault status register (in ms) */ | ||
37 | #define TAS5720_FAULT_CHECK_INTERVAL 200 | ||
38 | |||
39 | static const char * const tas5720_supply_names[] = { | ||
40 | "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ | ||
41 | "pvdd", /* Class-D amp and analog power supply (connected). */ | ||
42 | }; | ||
43 | |||
44 | #define TAS5720_NUM_SUPPLIES ARRAY_SIZE(tas5720_supply_names) | ||
45 | |||
46 | struct tas5720_data { | ||
47 | struct snd_soc_codec *codec; | ||
48 | struct regmap *regmap; | ||
49 | struct i2c_client *tas5720_client; | ||
50 | struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES]; | ||
51 | struct delayed_work fault_check_work; | ||
52 | unsigned int last_fault; | ||
53 | }; | ||
54 | |||
55 | static int tas5720_hw_params(struct snd_pcm_substream *substream, | ||
56 | struct snd_pcm_hw_params *params, | ||
57 | struct snd_soc_dai *dai) | ||
58 | { | ||
59 | struct snd_soc_codec *codec = dai->codec; | ||
60 | unsigned int rate = params_rate(params); | ||
61 | bool ssz_ds; | ||
62 | int ret; | ||
63 | |||
64 | switch (rate) { | ||
65 | case 44100: | ||
66 | case 48000: | ||
67 | ssz_ds = false; | ||
68 | break; | ||
69 | case 88200: | ||
70 | case 96000: | ||
71 | ssz_ds = true; | ||
72 | break; | ||
73 | default: | ||
74 | dev_err(codec->dev, "unsupported sample rate: %u\n", rate); | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | |||
78 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG, | ||
79 | TAS5720_SSZ_DS, ssz_ds); | ||
80 | if (ret < 0) { | ||
81 | dev_err(codec->dev, "error setting sample rate: %d\n", ret); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
89 | { | ||
90 | struct snd_soc_codec *codec = dai->codec; | ||
91 | u8 serial_format; | ||
92 | int ret; | ||
93 | |||
94 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { | ||
95 | dev_vdbg(codec->dev, "DAI Format master is not found\n"); | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | | ||
100 | SND_SOC_DAIFMT_INV_MASK)) { | ||
101 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): | ||
102 | /* 1st data bit occur one BCLK cycle after the frame sync */ | ||
103 | serial_format = TAS5720_SAIF_I2S; | ||
104 | break; | ||
105 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF): | ||
106 | /* | ||
107 | * Note that although the TAS5720 does not have a dedicated DSP | ||
108 | * mode it doesn't care about the LRCLK duty cycle during TDM | ||
109 | * operation. Therefore we can use the device's I2S mode with | ||
110 | * its delaying of the 1st data bit to receive DSP_A formatted | ||
111 | * data. See device datasheet for additional details. | ||
112 | */ | ||
113 | serial_format = TAS5720_SAIF_I2S; | ||
114 | break; | ||
115 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF): | ||
116 | /* | ||
117 | * Similar to DSP_A, we can use the fact that the TAS5720 does | ||
118 | * not care about the LRCLK duty cycle during TDM to receive | ||
119 | * DSP_B formatted data in LEFTJ mode (no delaying of the 1st | ||
120 | * data bit). | ||
121 | */ | ||
122 | serial_format = TAS5720_SAIF_LEFTJ; | ||
123 | break; | ||
124 | case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF): | ||
125 | /* No delay after the frame sync */ | ||
126 | serial_format = TAS5720_SAIF_LEFTJ; | ||
127 | break; | ||
128 | default: | ||
129 | dev_vdbg(codec->dev, "DAI Format is not found\n"); | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | |||
133 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG, | ||
134 | TAS5720_SAIF_FORMAT_MASK, | ||
135 | serial_format); | ||
136 | if (ret < 0) { | ||
137 | dev_err(codec->dev, "error setting SAIF format: %d\n", ret); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, | ||
145 | unsigned int tx_mask, unsigned int rx_mask, | ||
146 | int slots, int slot_width) | ||
147 | { | ||
148 | struct snd_soc_codec *codec = dai->codec; | ||
149 | unsigned int first_slot; | ||
150 | int ret; | ||
151 | |||
152 | if (!tx_mask) { | ||
153 | dev_err(codec->dev, "tx masks must not be 0\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Determine the first slot that is being requested. We will only | ||
159 | * use the first slot that is found since the TAS5720 is a mono | ||
160 | * amplifier. | ||
161 | */ | ||
162 | first_slot = __ffs(tx_mask); | ||
163 | |||
164 | if (first_slot > 7) { | ||
165 | dev_err(codec->dev, "slot selection out of bounds (%u)\n", | ||
166 | first_slot); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | /* Enable manual TDM slot selection (instead of I2C ID based) */ | ||
171 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG, | ||
172 | TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC); | ||
173 | if (ret < 0) | ||
174 | goto error_snd_soc_update_bits; | ||
175 | |||
176 | /* Configure the TDM slot to process audio from */ | ||
177 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, | ||
178 | TAS5720_TDM_SLOT_SEL_MASK, first_slot); | ||
179 | if (ret < 0) | ||
180 | goto error_snd_soc_update_bits; | ||
181 | |||
182 | return 0; | ||
183 | |||
184 | error_snd_soc_update_bits: | ||
185 | dev_err(codec->dev, "error configuring TDM mode: %d\n", ret); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int tas5720_mute(struct snd_soc_dai *dai, int mute) | ||
190 | { | ||
191 | struct snd_soc_codec *codec = dai->codec; | ||
192 | int ret; | ||
193 | |||
194 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, | ||
195 | TAS5720_MUTE, mute ? TAS5720_MUTE : 0); | ||
196 | if (ret < 0) { | ||
197 | dev_err(codec->dev, "error (un-)muting device: %d\n", ret); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static void tas5720_fault_check_work(struct work_struct *work) | ||
205 | { | ||
206 | struct tas5720_data *tas5720 = container_of(work, struct tas5720_data, | ||
207 | fault_check_work.work); | ||
208 | struct device *dev = tas5720->codec->dev; | ||
209 | unsigned int curr_fault; | ||
210 | int ret; | ||
211 | |||
212 | ret = regmap_read(tas5720->regmap, TAS5720_FAULT_REG, &curr_fault); | ||
213 | if (ret < 0) { | ||
214 | dev_err(dev, "failed to read FAULT register: %d\n", ret); | ||
215 | goto out; | ||
216 | } | ||
217 | |||
218 | /* Check/handle all errors except SAIF clock errors */ | ||
219 | curr_fault &= TAS5720_OCE | TAS5720_DCE | TAS5720_OTE; | ||
220 | |||
221 | /* | ||
222 | * Only flag errors once for a given occurrence. This is needed as | ||
223 | * the TAS5720 will take time clearing the fault condition internally | ||
224 | * during which we don't want to bombard the system with the same | ||
225 | * error message over and over. | ||
226 | */ | ||
227 | if ((curr_fault & TAS5720_OCE) && !(tas5720->last_fault & TAS5720_OCE)) | ||
228 | dev_crit(dev, "experienced an over current hardware fault\n"); | ||
229 | |||
230 | if ((curr_fault & TAS5720_DCE) && !(tas5720->last_fault & TAS5720_DCE)) | ||
231 | dev_crit(dev, "experienced a DC detection fault\n"); | ||
232 | |||
233 | if ((curr_fault & TAS5720_OTE) && !(tas5720->last_fault & TAS5720_OTE)) | ||
234 | dev_crit(dev, "experienced an over temperature fault\n"); | ||
235 | |||
236 | /* Store current fault value so we can detect any changes next time */ | ||
237 | tas5720->last_fault = curr_fault; | ||
238 | |||
239 | if (!curr_fault) | ||
240 | goto out; | ||
241 | |||
242 | /* | ||
243 | * Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching | ||
244 | * faults as long as a fault condition persists. Always going through | ||
245 | * the full sequence no matter the first return value to minimizes | ||
246 | * chances for the device to end up in shutdown mode. | ||
247 | */ | ||
248 | ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG, | ||
249 | TAS5720_SDZ, 0); | ||
250 | if (ret < 0) | ||
251 | dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret); | ||
252 | |||
253 | ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG, | ||
254 | TAS5720_SDZ, TAS5720_SDZ); | ||
255 | if (ret < 0) | ||
256 | dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret); | ||
257 | |||
258 | out: | ||
259 | /* Schedule the next fault check at the specified interval */ | ||
260 | schedule_delayed_work(&tas5720->fault_check_work, | ||
261 | msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL)); | ||
262 | } | ||
263 | |||
264 | static int tas5720_codec_probe(struct snd_soc_codec *codec) | ||
265 | { | ||
266 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
267 | unsigned int device_id; | ||
268 | int ret; | ||
269 | |||
270 | tas5720->codec = codec; | ||
271 | |||
272 | ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies), | ||
273 | tas5720->supplies); | ||
274 | if (ret != 0) { | ||
275 | dev_err(codec->dev, "failed to enable supplies: %d\n", ret); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id); | ||
280 | if (ret < 0) { | ||
281 | dev_err(codec->dev, "failed to read device ID register: %d\n", | ||
282 | ret); | ||
283 | goto probe_fail; | ||
284 | } | ||
285 | |||
286 | if (device_id != TAS5720_DEVICE_ID) { | ||
287 | dev_err(codec->dev, "wrong device ID. expected: %u read: %u\n", | ||
288 | TAS5720_DEVICE_ID, device_id); | ||
289 | ret = -ENODEV; | ||
290 | goto probe_fail; | ||
291 | } | ||
292 | |||
293 | /* Set device to mute */ | ||
294 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, | ||
295 | TAS5720_MUTE, TAS5720_MUTE); | ||
296 | if (ret < 0) | ||
297 | goto error_snd_soc_update_bits; | ||
298 | |||
299 | /* | ||
300 | * Enter shutdown mode - our default when not playing audio - to | ||
301 | * minimize current consumption. On the TAS5720 there is no real down | ||
302 | * side doing so as all device registers are preserved and the wakeup | ||
303 | * of the codec is rather quick which we do using a dapm widget. | ||
304 | */ | ||
305 | ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG, | ||
306 | TAS5720_SDZ, 0); | ||
307 | if (ret < 0) | ||
308 | goto error_snd_soc_update_bits; | ||
309 | |||
310 | INIT_DELAYED_WORK(&tas5720->fault_check_work, tas5720_fault_check_work); | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | error_snd_soc_update_bits: | ||
315 | dev_err(codec->dev, "error configuring device registers: %d\n", ret); | ||
316 | |||
317 | probe_fail: | ||
318 | regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies), | ||
319 | tas5720->supplies); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | static int tas5720_codec_remove(struct snd_soc_codec *codec) | ||
324 | { | ||
325 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
326 | int ret; | ||
327 | |||
328 | cancel_delayed_work_sync(&tas5720->fault_check_work); | ||
329 | |||
330 | ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies), | ||
331 | tas5720->supplies); | ||
332 | if (ret < 0) | ||
333 | dev_err(codec->dev, "failed to disable supplies: %d\n", ret); | ||
334 | |||
335 | return ret; | ||
336 | }; | ||
337 | |||
338 | static int tas5720_dac_event(struct snd_soc_dapm_widget *w, | ||
339 | struct snd_kcontrol *kcontrol, int event) | ||
340 | { | ||
341 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
342 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
343 | int ret; | ||
344 | |||
345 | if (event & SND_SOC_DAPM_POST_PMU) { | ||
346 | /* Take TAS5720 out of shutdown mode */ | ||
347 | ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG, | ||
348 | TAS5720_SDZ, TAS5720_SDZ); | ||
349 | if (ret < 0) { | ||
350 | dev_err(codec->dev, "error waking codec: %d\n", ret); | ||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Observe codec shutdown-to-active time. The datasheet only | ||
356 | * lists a nominal value however just use-it as-is without | ||
357 | * additional padding to minimize the delay introduced in | ||
358 | * starting to play audio (actually there is other setup done | ||
359 | * by the ASoC framework that will provide additional delays, | ||
360 | * so we should always be safe). | ||
361 | */ | ||
362 | msleep(25); | ||
363 | |||
364 | /* Turn on TAS5720 periodic fault checking/handling */ | ||
365 | tas5720->last_fault = 0; | ||
366 | schedule_delayed_work(&tas5720->fault_check_work, | ||
367 | msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL)); | ||
368 | } else if (event & SND_SOC_DAPM_PRE_PMD) { | ||
369 | /* Disable TAS5720 periodic fault checking/handling */ | ||
370 | cancel_delayed_work_sync(&tas5720->fault_check_work); | ||
371 | |||
372 | /* Place TAS5720 in shutdown mode to minimize current draw */ | ||
373 | ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG, | ||
374 | TAS5720_SDZ, 0); | ||
375 | if (ret < 0) { | ||
376 | dev_err(codec->dev, "error shutting down codec: %d\n", | ||
377 | ret); | ||
378 | return ret; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | #ifdef CONFIG_PM | ||
386 | static int tas5720_suspend(struct snd_soc_codec *codec) | ||
387 | { | ||
388 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
389 | int ret; | ||
390 | |||
391 | regcache_cache_only(tas5720->regmap, true); | ||
392 | regcache_mark_dirty(tas5720->regmap); | ||
393 | |||
394 | ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies), | ||
395 | tas5720->supplies); | ||
396 | if (ret < 0) | ||
397 | dev_err(codec->dev, "failed to disable supplies: %d\n", ret); | ||
398 | |||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static int tas5720_resume(struct snd_soc_codec *codec) | ||
403 | { | ||
404 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
405 | int ret; | ||
406 | |||
407 | ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies), | ||
408 | tas5720->supplies); | ||
409 | if (ret < 0) { | ||
410 | dev_err(codec->dev, "failed to enable supplies: %d\n", ret); | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | regcache_cache_only(tas5720->regmap, false); | ||
415 | |||
416 | ret = regcache_sync(tas5720->regmap); | ||
417 | if (ret < 0) { | ||
418 | dev_err(codec->dev, "failed to sync regcache: %d\n", ret); | ||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | #else | ||
425 | #define tas5720_suspend NULL | ||
426 | #define tas5720_resume NULL | ||
427 | #endif | ||
428 | |||
429 | static bool tas5720_is_volatile_reg(struct device *dev, unsigned int reg) | ||
430 | { | ||
431 | switch (reg) { | ||
432 | case TAS5720_DEVICE_ID_REG: | ||
433 | case TAS5720_FAULT_REG: | ||
434 | return true; | ||
435 | default: | ||
436 | return false; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | static const struct regmap_config tas5720_regmap_config = { | ||
441 | .reg_bits = 8, | ||
442 | .val_bits = 8, | ||
443 | |||
444 | .max_register = TAS5720_MAX_REG, | ||
445 | .cache_type = REGCACHE_RBTREE, | ||
446 | .volatile_reg = tas5720_is_volatile_reg, | ||
447 | }; | ||
448 | |||
449 | /* | ||
450 | * DAC analog gain. There are four discrete values to select from, ranging | ||
451 | * from 19.2 dB to 26.3dB. | ||
452 | */ | ||
453 | static const DECLARE_TLV_DB_RANGE(dac_analog_tlv, | ||
454 | 0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0), | ||
455 | 0x1, 0x1, TLV_DB_SCALE_ITEM(2070, 0, 0), | ||
456 | 0x2, 0x2, TLV_DB_SCALE_ITEM(2350, 0, 0), | ||
457 | 0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0), | ||
458 | ); | ||
459 | |||
460 | /* | ||
461 | * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that | ||
462 | * setting the gain below -100 dB (register value <0x7) is effectively a MUTE | ||
463 | * as per device datasheet. | ||
464 | */ | ||
465 | static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); | ||
466 | |||
467 | static const struct snd_kcontrol_new tas5720_snd_controls[] = { | ||
468 | SOC_SINGLE_TLV("Speaker Driver Playback Volume", | ||
469 | TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), | ||
470 | SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, | ||
471 | TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), | ||
472 | }; | ||
473 | |||
474 | static const struct snd_soc_dapm_widget tas5720_dapm_widgets[] = { | ||
475 | SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
476 | SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas5720_dac_event, | ||
477 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
478 | SND_SOC_DAPM_OUTPUT("OUT") | ||
479 | }; | ||
480 | |||
481 | static const struct snd_soc_dapm_route tas5720_audio_map[] = { | ||
482 | { "DAC", NULL, "DAC IN" }, | ||
483 | { "OUT", NULL, "DAC" }, | ||
484 | }; | ||
485 | |||
486 | static struct snd_soc_codec_driver soc_codec_dev_tas5720 = { | ||
487 | .probe = tas5720_codec_probe, | ||
488 | .remove = tas5720_codec_remove, | ||
489 | .suspend = tas5720_suspend, | ||
490 | .resume = tas5720_resume, | ||
491 | |||
492 | .controls = tas5720_snd_controls, | ||
493 | .num_controls = ARRAY_SIZE(tas5720_snd_controls), | ||
494 | .dapm_widgets = tas5720_dapm_widgets, | ||
495 | .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets), | ||
496 | .dapm_routes = tas5720_audio_map, | ||
497 | .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map), | ||
498 | }; | ||
499 | |||
500 | /* PCM rates supported by the TAS5720 driver */ | ||
501 | #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ | ||
502 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
503 | |||
504 | /* Formats supported by TAS5720 driver */ | ||
505 | #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ | ||
506 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
507 | |||
508 | static struct snd_soc_dai_ops tas5720_speaker_dai_ops = { | ||
509 | .hw_params = tas5720_hw_params, | ||
510 | .set_fmt = tas5720_set_dai_fmt, | ||
511 | .set_tdm_slot = tas5720_set_dai_tdm_slot, | ||
512 | .digital_mute = tas5720_mute, | ||
513 | }; | ||
514 | |||
515 | /* | ||
516 | * TAS5720 DAI structure | ||
517 | * | ||
518 | * Note that were are advertising .playback.channels_max = 2 despite this being | ||
519 | * a mono amplifier. The reason for that is that some serial ports such as TI's | ||
520 | * McASP module have a minimum number of channels (2) that they can output. | ||
521 | * Advertising more channels than we have will allow us to interface with such | ||
522 | * a serial port without really any negative side effects as the TAS5720 will | ||
523 | * simply ignore any extra channel(s) asides from the one channel that is | ||
524 | * configured to be played back. | ||
525 | */ | ||
526 | static struct snd_soc_dai_driver tas5720_dai[] = { | ||
527 | { | ||
528 | .name = "tas5720-amplifier", | ||
529 | .playback = { | ||
530 | .stream_name = "Playback", | ||
531 | .channels_min = 1, | ||
532 | .channels_max = 2, | ||
533 | .rates = TAS5720_RATES, | ||
534 | .formats = TAS5720_FORMATS, | ||
535 | }, | ||
536 | .ops = &tas5720_speaker_dai_ops, | ||
537 | }, | ||
538 | }; | ||
539 | |||
540 | static int tas5720_probe(struct i2c_client *client, | ||
541 | const struct i2c_device_id *id) | ||
542 | { | ||
543 | struct device *dev = &client->dev; | ||
544 | struct tas5720_data *data; | ||
545 | int ret; | ||
546 | int i; | ||
547 | |||
548 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | ||
549 | if (!data) | ||
550 | return -ENOMEM; | ||
551 | |||
552 | data->tas5720_client = client; | ||
553 | data->regmap = devm_regmap_init_i2c(client, &tas5720_regmap_config); | ||
554 | if (IS_ERR(data->regmap)) { | ||
555 | ret = PTR_ERR(data->regmap); | ||
556 | dev_err(dev, "failed to allocate register map: %d\n", ret); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | ||
561 | data->supplies[i].supply = tas5720_supply_names[i]; | ||
562 | |||
563 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), | ||
564 | data->supplies); | ||
565 | if (ret != 0) { | ||
566 | dev_err(dev, "failed to request supplies: %d\n", ret); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | dev_set_drvdata(dev, data); | ||
571 | |||
572 | ret = snd_soc_register_codec(&client->dev, | ||
573 | &soc_codec_dev_tas5720, | ||
574 | tas5720_dai, ARRAY_SIZE(tas5720_dai)); | ||
575 | if (ret < 0) { | ||
576 | dev_err(dev, "failed to register codec: %d\n", ret); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int tas5720_remove(struct i2c_client *client) | ||
584 | { | ||
585 | struct device *dev = &client->dev; | ||
586 | |||
587 | snd_soc_unregister_codec(dev); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static const struct i2c_device_id tas5720_id[] = { | ||
593 | { "tas5720", 0 }, | ||
594 | { } | ||
595 | }; | ||
596 | MODULE_DEVICE_TABLE(i2c, tas5720_id); | ||
597 | |||
598 | #if IS_ENABLED(CONFIG_OF) | ||
599 | static const struct of_device_id tas5720_of_match[] = { | ||
600 | { .compatible = "ti,tas5720", }, | ||
601 | { }, | ||
602 | }; | ||
603 | MODULE_DEVICE_TABLE(of, tas5720_of_match); | ||
604 | #endif | ||
605 | |||
606 | static struct i2c_driver tas5720_i2c_driver = { | ||
607 | .driver = { | ||
608 | .name = "tas5720", | ||
609 | .of_match_table = of_match_ptr(tas5720_of_match), | ||
610 | }, | ||
611 | .probe = tas5720_probe, | ||
612 | .remove = tas5720_remove, | ||
613 | .id_table = tas5720_id, | ||
614 | }; | ||
615 | |||
616 | module_i2c_driver(tas5720_i2c_driver); | ||
617 | |||
618 | MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>"); | ||
619 | MODULE_DESCRIPTION("TAS5720 Audio amplifier driver"); | ||
620 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h new file mode 100644 index 000000000000..3d077c779b12 --- /dev/null +++ b/sound/soc/codecs/tas5720.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * tas5720.h - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier | ||
3 | * | ||
4 | * Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Author: Andreas Dannenberg <dannenberg@ti.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef __TAS5720_H__ | ||
19 | #define __TAS5720_H__ | ||
20 | |||
21 | /* Register Address Map */ | ||
22 | #define TAS5720_DEVICE_ID_REG 0x00 | ||
23 | #define TAS5720_POWER_CTRL_REG 0x01 | ||
24 | #define TAS5720_DIGITAL_CTRL1_REG 0x02 | ||
25 | #define TAS5720_DIGITAL_CTRL2_REG 0x03 | ||
26 | #define TAS5720_VOLUME_CTRL_REG 0x04 | ||
27 | #define TAS5720_ANALOG_CTRL_REG 0x06 | ||
28 | #define TAS5720_FAULT_REG 0x08 | ||
29 | #define TAS5720_DIGITAL_CLIP2_REG 0x10 | ||
30 | #define TAS5720_DIGITAL_CLIP1_REG 0x11 | ||
31 | #define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG | ||
32 | |||
33 | /* TAS5720_DEVICE_ID_REG */ | ||
34 | #define TAS5720_DEVICE_ID 0x01 | ||
35 | |||
36 | /* TAS5720_POWER_CTRL_REG */ | ||
37 | #define TAS5720_DIG_CLIP_MASK GENMASK(7, 2) | ||
38 | #define TAS5720_SLEEP BIT(1) | ||
39 | #define TAS5720_SDZ BIT(0) | ||
40 | |||
41 | /* TAS5720_DIGITAL_CTRL1_REG */ | ||
42 | #define TAS5720_HPF_BYPASS BIT(7) | ||
43 | #define TAS5720_TDM_CFG_SRC BIT(6) | ||
44 | #define TAS5720_SSZ_DS BIT(3) | ||
45 | #define TAS5720_SAIF_RIGHTJ_24BIT (0x0) | ||
46 | #define TAS5720_SAIF_RIGHTJ_20BIT (0x1) | ||
47 | #define TAS5720_SAIF_RIGHTJ_18BIT (0x2) | ||
48 | #define TAS5720_SAIF_RIGHTJ_16BIT (0x3) | ||
49 | #define TAS5720_SAIF_I2S (0x4) | ||
50 | #define TAS5720_SAIF_LEFTJ (0x5) | ||
51 | #define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0) | ||
52 | |||
53 | /* TAS5720_DIGITAL_CTRL2_REG */ | ||
54 | #define TAS5720_MUTE BIT(4) | ||
55 | #define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0) | ||
56 | |||
57 | /* TAS5720_ANALOG_CTRL_REG */ | ||
58 | #define TAS5720_PWM_RATE_6_3_FSYNC (0x0 << 4) | ||
59 | #define TAS5720_PWM_RATE_8_4_FSYNC (0x1 << 4) | ||
60 | #define TAS5720_PWM_RATE_10_5_FSYNC (0x2 << 4) | ||
61 | #define TAS5720_PWM_RATE_12_6_FSYNC (0x3 << 4) | ||
62 | #define TAS5720_PWM_RATE_14_7_FSYNC (0x4 << 4) | ||
63 | #define TAS5720_PWM_RATE_16_8_FSYNC (0x5 << 4) | ||
64 | #define TAS5720_PWM_RATE_20_10_FSYNC (0x6 << 4) | ||
65 | #define TAS5720_PWM_RATE_24_12_FSYNC (0x7 << 4) | ||
66 | #define TAS5720_PWM_RATE_MASK GENMASK(6, 4) | ||
67 | #define TAS5720_ANALOG_GAIN_19_2DBV (0x0 << 2) | ||
68 | #define TAS5720_ANALOG_GAIN_20_7DBV (0x1 << 2) | ||
69 | #define TAS5720_ANALOG_GAIN_23_5DBV (0x2 << 2) | ||
70 | #define TAS5720_ANALOG_GAIN_26_3DBV (0x3 << 2) | ||
71 | #define TAS5720_ANALOG_GAIN_MASK GENMASK(3, 2) | ||
72 | #define TAS5720_ANALOG_GAIN_SHIFT (0x2) | ||
73 | |||
74 | /* TAS5720_FAULT_REG */ | ||
75 | #define TAS5720_OC_THRESH_100PCT (0x0 << 4) | ||
76 | #define TAS5720_OC_THRESH_75PCT (0x1 << 4) | ||
77 | #define TAS5720_OC_THRESH_50PCT (0x2 << 4) | ||
78 | #define TAS5720_OC_THRESH_25PCT (0x3 << 4) | ||
79 | #define TAS5720_OC_THRESH_MASK GENMASK(5, 4) | ||
80 | #define TAS5720_CLKE BIT(3) | ||
81 | #define TAS5720_OCE BIT(2) | ||
82 | #define TAS5720_DCE BIT(1) | ||
83 | #define TAS5720_OTE BIT(0) | ||
84 | #define TAS5720_FAULT_MASK GENMASK(3, 0) | ||
85 | |||
86 | /* TAS5720_DIGITAL_CLIP1_REG */ | ||
87 | #define TAS5720_CLIP1_MASK GENMASK(7, 2) | ||
88 | #define TAS5720_CLIP1_SHIFT (0x2) | ||
89 | |||
90 | #endif /* __TAS5720_H__ */ | ||
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index ee4def4f819f..3c5e1df01c19 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
29 | #include <linux/gpio.h> | 29 | #include <linux/gpio.h> |
30 | #include <linux/regulator/consumer.h> | 30 | #include <linux/regulator/consumer.h> |
31 | #include <linux/acpi.h> | ||
31 | #include <linux/of.h> | 32 | #include <linux/of.h> |
32 | #include <linux/of_gpio.h> | 33 | #include <linux/of_gpio.h> |
33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
@@ -1280,10 +1281,19 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { | |||
1280 | }; | 1281 | }; |
1281 | MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); | 1282 | MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); |
1282 | 1283 | ||
1284 | #ifdef CONFIG_ACPI | ||
1285 | static const struct acpi_device_id aic31xx_acpi_match[] = { | ||
1286 | { "10TI3100", 0 }, | ||
1287 | { } | ||
1288 | }; | ||
1289 | MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); | ||
1290 | #endif | ||
1291 | |||
1283 | static struct i2c_driver aic31xx_i2c_driver = { | 1292 | static struct i2c_driver aic31xx_i2c_driver = { |
1284 | .driver = { | 1293 | .driver = { |
1285 | .name = "tlv320aic31xx-codec", | 1294 | .name = "tlv320aic31xx-codec", |
1286 | .of_match_table = of_match_ptr(tlv320aic31xx_of_match), | 1295 | .of_match_table = of_match_ptr(tlv320aic31xx_of_match), |
1296 | .acpi_match_table = ACPI_PTR(aic31xx_acpi_match), | ||
1287 | }, | 1297 | }, |
1288 | .probe = aic31xx_i2c_probe, | 1298 | .probe = aic31xx_i2c_probe, |
1289 | .remove = aic31xx_i2c_remove, | 1299 | .remove = aic31xx_i2c_remove, |
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c new file mode 100644 index 000000000000..59606cf3008f --- /dev/null +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/codecs/tlv320aic32x4-i2c.c | ||
3 | * | ||
4 | * Copyright 2011 NW Digital Radio | ||
5 | * | ||
6 | * Author: Jeremy McDermond <nh6z@nh6z.net> | ||
7 | * | ||
8 | * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "tlv320aic32x4.h" | ||
28 | |||
29 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | ||
30 | const struct i2c_device_id *id) | ||
31 | { | ||
32 | struct regmap *regmap; | ||
33 | struct regmap_config config; | ||
34 | |||
35 | config = aic32x4_regmap_config; | ||
36 | config.reg_bits = 8; | ||
37 | config.val_bits = 8; | ||
38 | |||
39 | regmap = devm_regmap_init_i2c(i2c, &config); | ||
40 | return aic32x4_probe(&i2c->dev, regmap); | ||
41 | } | ||
42 | |||
43 | static int aic32x4_i2c_remove(struct i2c_client *i2c) | ||
44 | { | ||
45 | return aic32x4_remove(&i2c->dev); | ||
46 | } | ||
47 | |||
48 | static const struct i2c_device_id aic32x4_i2c_id[] = { | ||
49 | { "tlv320aic32x4", 0 }, | ||
50 | { /* sentinel */ } | ||
51 | }; | ||
52 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); | ||
53 | |||
54 | static const struct of_device_id aic32x4_of_id[] = { | ||
55 | { .compatible = "ti,tlv320aic32x4", }, | ||
56 | { /* senitel */ } | ||
57 | }; | ||
58 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
59 | |||
60 | static struct i2c_driver aic32x4_i2c_driver = { | ||
61 | .driver = { | ||
62 | .name = "tlv320aic32x4", | ||
63 | .of_match_table = aic32x4_of_id, | ||
64 | }, | ||
65 | .probe = aic32x4_i2c_probe, | ||
66 | .remove = aic32x4_i2c_remove, | ||
67 | .id_table = aic32x4_i2c_id, | ||
68 | }; | ||
69 | |||
70 | module_i2c_driver(aic32x4_i2c_driver); | ||
71 | |||
72 | MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C"); | ||
73 | MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>"); | ||
74 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c new file mode 100644 index 000000000000..724fcdd491b2 --- /dev/null +++ b/sound/soc/codecs/tlv320aic32x4-spi.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/codecs/tlv320aic32x4-spi.c | ||
3 | * | ||
4 | * Copyright 2011 NW Digital Radio | ||
5 | * | ||
6 | * Author: Jeremy McDermond <nh6z@nh6z.net> | ||
7 | * | ||
8 | * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "tlv320aic32x4.h" | ||
28 | |||
29 | static int aic32x4_spi_probe(struct spi_device *spi) | ||
30 | { | ||
31 | struct regmap *regmap; | ||
32 | struct regmap_config config; | ||
33 | |||
34 | config = aic32x4_regmap_config; | ||
35 | config.reg_bits = 7; | ||
36 | config.pad_bits = 1; | ||
37 | config.val_bits = 8; | ||
38 | config.read_flag_mask = 0x01; | ||
39 | |||
40 | regmap = devm_regmap_init_spi(spi, &config); | ||
41 | return aic32x4_probe(&spi->dev, regmap); | ||
42 | } | ||
43 | |||
44 | static int aic32x4_spi_remove(struct spi_device *spi) | ||
45 | { | ||
46 | return aic32x4_remove(&spi->dev); | ||
47 | } | ||
48 | |||
49 | static const struct spi_device_id aic32x4_spi_id[] = { | ||
50 | { "tlv320aic32x4", 0 }, | ||
51 | { /* sentinel */ } | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(spi, aic32x4_spi_id); | ||
54 | |||
55 | static const struct of_device_id aic32x4_of_id[] = { | ||
56 | { .compatible = "ti,tlv320aic32x4", }, | ||
57 | { /* senitel */ } | ||
58 | }; | ||
59 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
60 | |||
61 | static struct spi_driver aic32x4_spi_driver = { | ||
62 | .driver = { | ||
63 | .name = "tlv320aic32x4", | ||
64 | .owner = THIS_MODULE, | ||
65 | .of_match_table = aic32x4_of_id, | ||
66 | }, | ||
67 | .probe = aic32x4_spi_probe, | ||
68 | .remove = aic32x4_spi_remove, | ||
69 | .id_table = aic32x4_spi_id, | ||
70 | }; | ||
71 | |||
72 | module_spi_driver(aic32x4_spi_driver); | ||
73 | |||
74 | MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI"); | ||
75 | MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>"); | ||
76 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index f2d3191961e1..85d4978d0384 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
32 | #include <linux/of_gpio.h> | 32 | #include <linux/of_gpio.h> |
33 | #include <linux/i2c.h> | ||
34 | #include <linux/cdev.h> | 33 | #include <linux/cdev.h> |
35 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
36 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
@@ -160,7 +159,10 @@ static const struct aic32x4_rate_divs aic32x4_divs[] = { | |||
160 | /* 48k rate */ | 159 | /* 48k rate */ |
161 | {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, | 160 | {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, |
162 | {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, | 161 | {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, |
163 | {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4} | 162 | {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}, |
163 | |||
164 | /* 96k rate */ | ||
165 | {AIC32X4_FREQ_25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1}, | ||
164 | }; | 166 | }; |
165 | 167 | ||
166 | static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { | 168 | static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { |
@@ -181,16 +183,71 @@ static const struct snd_kcontrol_new lor_output_mixer_controls[] = { | |||
181 | SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0), | 183 | SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0), |
182 | }; | 184 | }; |
183 | 185 | ||
184 | static const struct snd_kcontrol_new left_input_mixer_controls[] = { | 186 | static const char * const resistor_text[] = { |
185 | SOC_DAPM_SINGLE("IN1_L P Switch", AIC32X4_LMICPGAPIN, 6, 1, 0), | 187 | "Off", "10 kOhm", "20 kOhm", "40 kOhm", |
186 | SOC_DAPM_SINGLE("IN2_L P Switch", AIC32X4_LMICPGAPIN, 4, 1, 0), | ||
187 | SOC_DAPM_SINGLE("IN3_L P Switch", AIC32X4_LMICPGAPIN, 2, 1, 0), | ||
188 | }; | 188 | }; |
189 | 189 | ||
190 | static const struct snd_kcontrol_new right_input_mixer_controls[] = { | 190 | /* Left mixer pins */ |
191 | SOC_DAPM_SINGLE("IN1_R P Switch", AIC32X4_RMICPGAPIN, 6, 1, 0), | 191 | static SOC_ENUM_SINGLE_DECL(in1l_lpga_p_enum, AIC32X4_LMICPGAPIN, 6, resistor_text); |
192 | SOC_DAPM_SINGLE("IN2_R P Switch", AIC32X4_RMICPGAPIN, 4, 1, 0), | 192 | static SOC_ENUM_SINGLE_DECL(in2l_lpga_p_enum, AIC32X4_LMICPGAPIN, 4, resistor_text); |
193 | SOC_DAPM_SINGLE("IN3_R P Switch", AIC32X4_RMICPGAPIN, 2, 1, 0), | 193 | static SOC_ENUM_SINGLE_DECL(in3l_lpga_p_enum, AIC32X4_LMICPGAPIN, 2, resistor_text); |
194 | static SOC_ENUM_SINGLE_DECL(in1r_lpga_p_enum, AIC32X4_LMICPGAPIN, 0, resistor_text); | ||
195 | |||
196 | static SOC_ENUM_SINGLE_DECL(cml_lpga_n_enum, AIC32X4_LMICPGANIN, 6, resistor_text); | ||
197 | static SOC_ENUM_SINGLE_DECL(in2r_lpga_n_enum, AIC32X4_LMICPGANIN, 4, resistor_text); | ||
198 | static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_text); | ||
199 | |||
200 | static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = { | ||
201 | SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum), | ||
202 | }; | ||
203 | static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = { | ||
204 | SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum), | ||
205 | }; | ||
206 | static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = { | ||
207 | SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum), | ||
208 | }; | ||
209 | static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = { | ||
210 | SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum), | ||
211 | }; | ||
212 | static const struct snd_kcontrol_new cml_to_lmixer_controls[] = { | ||
213 | SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum), | ||
214 | }; | ||
215 | static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = { | ||
216 | SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum), | ||
217 | }; | ||
218 | static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = { | ||
219 | SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum), | ||
220 | }; | ||
221 | |||
222 | /* Right mixer pins */ | ||
223 | static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text); | ||
224 | static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text); | ||
225 | static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text); | ||
226 | static SOC_ENUM_SINGLE_DECL(in2l_rpga_p_enum, AIC32X4_RMICPGAPIN, 0, resistor_text); | ||
227 | static SOC_ENUM_SINGLE_DECL(cmr_rpga_n_enum, AIC32X4_RMICPGANIN, 6, resistor_text); | ||
228 | static SOC_ENUM_SINGLE_DECL(in1l_rpga_n_enum, AIC32X4_RMICPGANIN, 4, resistor_text); | ||
229 | static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_text); | ||
230 | |||
231 | static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = { | ||
232 | SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum), | ||
233 | }; | ||
234 | static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = { | ||
235 | SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum), | ||
236 | }; | ||
237 | static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = { | ||
238 | SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum), | ||
239 | }; | ||
240 | static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = { | ||
241 | SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum), | ||
242 | }; | ||
243 | static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = { | ||
244 | SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum), | ||
245 | }; | ||
246 | static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = { | ||
247 | SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum), | ||
248 | }; | ||
249 | static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = { | ||
250 | SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum), | ||
194 | }; | 251 | }; |
195 | 252 | ||
196 | static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { | 253 | static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { |
@@ -214,14 +271,39 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { | |||
214 | &lor_output_mixer_controls[0], | 271 | &lor_output_mixer_controls[0], |
215 | ARRAY_SIZE(lor_output_mixer_controls)), | 272 | ARRAY_SIZE(lor_output_mixer_controls)), |
216 | SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0), | 273 | SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0), |
217 | SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, | 274 | |
218 | &left_input_mixer_controls[0], | ||
219 | ARRAY_SIZE(left_input_mixer_controls)), | ||
220 | SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, | ||
221 | &right_input_mixer_controls[0], | ||
222 | ARRAY_SIZE(right_input_mixer_controls)), | ||
223 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), | ||
224 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), | 275 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), |
276 | SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
277 | in1r_to_rmixer_controls), | ||
278 | SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
279 | in2r_to_rmixer_controls), | ||
280 | SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
281 | in3r_to_rmixer_controls), | ||
282 | SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
283 | in2l_to_rmixer_controls), | ||
284 | SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
285 | cmr_to_rmixer_controls), | ||
286 | SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
287 | in1l_to_rmixer_controls), | ||
288 | SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
289 | in3l_to_rmixer_controls), | ||
290 | |||
291 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), | ||
292 | SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
293 | in1l_to_lmixer_controls), | ||
294 | SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
295 | in2l_to_lmixer_controls), | ||
296 | SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
297 | in3l_to_lmixer_controls), | ||
298 | SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
299 | in1r_to_lmixer_controls), | ||
300 | SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
301 | cml_to_lmixer_controls), | ||
302 | SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
303 | in2r_to_lmixer_controls), | ||
304 | SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
305 | in3r_to_lmixer_controls), | ||
306 | |||
225 | SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), | 307 | SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), |
226 | 308 | ||
227 | SND_SOC_DAPM_OUTPUT("HPL"), | 309 | SND_SOC_DAPM_OUTPUT("HPL"), |
@@ -261,19 +343,77 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { | |||
261 | {"LOR Power", NULL, "LOR Output Mixer"}, | 343 | {"LOR Power", NULL, "LOR Output Mixer"}, |
262 | {"LOR", NULL, "LOR Power"}, | 344 | {"LOR", NULL, "LOR Power"}, |
263 | 345 | ||
264 | /* Left input */ | ||
265 | {"Left Input Mixer", "IN1_L P Switch", "IN1_L"}, | ||
266 | {"Left Input Mixer", "IN2_L P Switch", "IN2_L"}, | ||
267 | {"Left Input Mixer", "IN3_L P Switch", "IN3_L"}, | ||
268 | |||
269 | {"Left ADC", NULL, "Left Input Mixer"}, | ||
270 | |||
271 | /* Right Input */ | 346 | /* Right Input */ |
272 | {"Right Input Mixer", "IN1_R P Switch", "IN1_R"}, | 347 | {"Right ADC", NULL, "IN1_R to Right Mixer Positive Resistor"}, |
273 | {"Right Input Mixer", "IN2_R P Switch", "IN2_R"}, | 348 | {"IN1_R to Right Mixer Positive Resistor", "10 kOhm", "IN1_R"}, |
274 | {"Right Input Mixer", "IN3_R P Switch", "IN3_R"}, | 349 | {"IN1_R to Right Mixer Positive Resistor", "20 kOhm", "IN1_R"}, |
275 | 350 | {"IN1_R to Right Mixer Positive Resistor", "40 kOhm", "IN1_R"}, | |
276 | {"Right ADC", NULL, "Right Input Mixer"}, | 351 | |
352 | {"Right ADC", NULL, "IN2_R to Right Mixer Positive Resistor"}, | ||
353 | {"IN2_R to Right Mixer Positive Resistor", "10 kOhm", "IN2_R"}, | ||
354 | {"IN2_R to Right Mixer Positive Resistor", "20 kOhm", "IN2_R"}, | ||
355 | {"IN2_R to Right Mixer Positive Resistor", "40 kOhm", "IN2_R"}, | ||
356 | |||
357 | {"Right ADC", NULL, "IN3_R to Right Mixer Positive Resistor"}, | ||
358 | {"IN3_R to Right Mixer Positive Resistor", "10 kOhm", "IN3_R"}, | ||
359 | {"IN3_R to Right Mixer Positive Resistor", "20 kOhm", "IN3_R"}, | ||
360 | {"IN3_R to Right Mixer Positive Resistor", "40 kOhm", "IN3_R"}, | ||
361 | |||
362 | {"Right ADC", NULL, "IN2_L to Right Mixer Positive Resistor"}, | ||
363 | {"IN2_L to Right Mixer Positive Resistor", "10 kOhm", "IN2_L"}, | ||
364 | {"IN2_L to Right Mixer Positive Resistor", "20 kOhm", "IN2_L"}, | ||
365 | {"IN2_L to Right Mixer Positive Resistor", "40 kOhm", "IN2_L"}, | ||
366 | |||
367 | {"Right ADC", NULL, "CM_R to Right Mixer Negative Resistor"}, | ||
368 | {"CM_R to Right Mixer Negative Resistor", "10 kOhm", "CM_R"}, | ||
369 | {"CM_R to Right Mixer Negative Resistor", "20 kOhm", "CM_R"}, | ||
370 | {"CM_R to Right Mixer Negative Resistor", "40 kOhm", "CM_R"}, | ||
371 | |||
372 | {"Right ADC", NULL, "IN1_L to Right Mixer Negative Resistor"}, | ||
373 | {"IN1_L to Right Mixer Negative Resistor", "10 kOhm", "IN1_L"}, | ||
374 | {"IN1_L to Right Mixer Negative Resistor", "20 kOhm", "IN1_L"}, | ||
375 | {"IN1_L to Right Mixer Negative Resistor", "40 kOhm", "IN1_L"}, | ||
376 | |||
377 | {"Right ADC", NULL, "IN3_L to Right Mixer Negative Resistor"}, | ||
378 | {"IN3_L to Right Mixer Negative Resistor", "10 kOhm", "IN3_L"}, | ||
379 | {"IN3_L to Right Mixer Negative Resistor", "20 kOhm", "IN3_L"}, | ||
380 | {"IN3_L to Right Mixer Negative Resistor", "40 kOhm", "IN3_L"}, | ||
381 | |||
382 | /* Left Input */ | ||
383 | {"Left ADC", NULL, "IN1_L to Left Mixer Positive Resistor"}, | ||
384 | {"IN1_L to Left Mixer Positive Resistor", "10 kOhm", "IN1_L"}, | ||
385 | {"IN1_L to Left Mixer Positive Resistor", "20 kOhm", "IN1_L"}, | ||
386 | {"IN1_L to Left Mixer Positive Resistor", "40 kOhm", "IN1_L"}, | ||
387 | |||
388 | {"Left ADC", NULL, "IN2_L to Left Mixer Positive Resistor"}, | ||
389 | {"IN2_L to Left Mixer Positive Resistor", "10 kOhm", "IN2_L"}, | ||
390 | {"IN2_L to Left Mixer Positive Resistor", "20 kOhm", "IN2_L"}, | ||
391 | {"IN2_L to Left Mixer Positive Resistor", "40 kOhm", "IN2_L"}, | ||
392 | |||
393 | {"Left ADC", NULL, "IN3_L to Left Mixer Positive Resistor"}, | ||
394 | {"IN3_L to Left Mixer Positive Resistor", "10 kOhm", "IN3_L"}, | ||
395 | {"IN3_L to Left Mixer Positive Resistor", "20 kOhm", "IN3_L"}, | ||
396 | {"IN3_L to Left Mixer Positive Resistor", "40 kOhm", "IN3_L"}, | ||
397 | |||
398 | {"Left ADC", NULL, "IN1_R to Left Mixer Positive Resistor"}, | ||
399 | {"IN1_R to Left Mixer Positive Resistor", "10 kOhm", "IN1_R"}, | ||
400 | {"IN1_R to Left Mixer Positive Resistor", "20 kOhm", "IN1_R"}, | ||
401 | {"IN1_R to Left Mixer Positive Resistor", "40 kOhm", "IN1_R"}, | ||
402 | |||
403 | {"Left ADC", NULL, "CM_L to Left Mixer Negative Resistor"}, | ||
404 | {"CM_L to Left Mixer Negative Resistor", "10 kOhm", "CM_L"}, | ||
405 | {"CM_L to Left Mixer Negative Resistor", "20 kOhm", "CM_L"}, | ||
406 | {"CM_L to Left Mixer Negative Resistor", "40 kOhm", "CM_L"}, | ||
407 | |||
408 | {"Left ADC", NULL, "IN2_R to Left Mixer Negative Resistor"}, | ||
409 | {"IN2_R to Left Mixer Negative Resistor", "10 kOhm", "IN2_R"}, | ||
410 | {"IN2_R to Left Mixer Negative Resistor", "20 kOhm", "IN2_R"}, | ||
411 | {"IN2_R to Left Mixer Negative Resistor", "40 kOhm", "IN2_R"}, | ||
412 | |||
413 | {"Left ADC", NULL, "IN3_R to Left Mixer Negative Resistor"}, | ||
414 | {"IN3_R to Left Mixer Negative Resistor", "10 kOhm", "IN3_R"}, | ||
415 | {"IN3_R to Left Mixer Negative Resistor", "20 kOhm", "IN3_R"}, | ||
416 | {"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"}, | ||
277 | }; | 417 | }; |
278 | 418 | ||
279 | static const struct regmap_range_cfg aic32x4_regmap_pages[] = { | 419 | static const struct regmap_range_cfg aic32x4_regmap_pages[] = { |
@@ -287,14 +427,12 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { | |||
287 | }, | 427 | }, |
288 | }; | 428 | }; |
289 | 429 | ||
290 | static const struct regmap_config aic32x4_regmap = { | 430 | const struct regmap_config aic32x4_regmap_config = { |
291 | .reg_bits = 8, | ||
292 | .val_bits = 8, | ||
293 | |||
294 | .max_register = AIC32X4_RMICPGAVOL, | 431 | .max_register = AIC32X4_RMICPGAVOL, |
295 | .ranges = aic32x4_regmap_pages, | 432 | .ranges = aic32x4_regmap_pages, |
296 | .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), | 433 | .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), |
297 | }; | 434 | }; |
435 | EXPORT_SYMBOL(aic32x4_regmap_config); | ||
298 | 436 | ||
299 | static inline int aic32x4_get_divs(int mclk, int rate) | 437 | static inline int aic32x4_get_divs(int mclk, int rate) |
300 | { | 438 | { |
@@ -567,7 +705,7 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, | |||
567 | return 0; | 705 | return 0; |
568 | } | 706 | } |
569 | 707 | ||
570 | #define AIC32X4_RATES SNDRV_PCM_RATE_8000_48000 | 708 | #define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000 |
571 | #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ | 709 | #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ |
572 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 710 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
573 | 711 | ||
@@ -596,7 +734,7 @@ static struct snd_soc_dai_driver aic32x4_dai = { | |||
596 | .symmetric_rates = 1, | 734 | .symmetric_rates = 1, |
597 | }; | 735 | }; |
598 | 736 | ||
599 | static int aic32x4_probe(struct snd_soc_codec *codec) | 737 | static int aic32x4_codec_probe(struct snd_soc_codec *codec) |
600 | { | 738 | { |
601 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | 739 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); |
602 | u32 tmp_reg; | 740 | u32 tmp_reg; |
@@ -655,7 +793,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
655 | } | 793 | } |
656 | 794 | ||
657 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | 795 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { |
658 | .probe = aic32x4_probe, | 796 | .probe = aic32x4_codec_probe, |
659 | .set_bias_level = aic32x4_set_bias_level, | 797 | .set_bias_level = aic32x4_set_bias_level, |
660 | .suspend_bias_off = true, | 798 | .suspend_bias_off = true, |
661 | 799 | ||
@@ -777,24 +915,22 @@ error_ldo: | |||
777 | return ret; | 915 | return ret; |
778 | } | 916 | } |
779 | 917 | ||
780 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | 918 | int aic32x4_probe(struct device *dev, struct regmap *regmap) |
781 | const struct i2c_device_id *id) | ||
782 | { | 919 | { |
783 | struct aic32x4_pdata *pdata = i2c->dev.platform_data; | ||
784 | struct aic32x4_priv *aic32x4; | 920 | struct aic32x4_priv *aic32x4; |
785 | struct device_node *np = i2c->dev.of_node; | 921 | struct aic32x4_pdata *pdata = dev->platform_data; |
922 | struct device_node *np = dev->of_node; | ||
786 | int ret; | 923 | int ret; |
787 | 924 | ||
788 | aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv), | 925 | if (IS_ERR(regmap)) |
926 | return PTR_ERR(regmap); | ||
927 | |||
928 | aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), | ||
789 | GFP_KERNEL); | 929 | GFP_KERNEL); |
790 | if (aic32x4 == NULL) | 930 | if (aic32x4 == NULL) |
791 | return -ENOMEM; | 931 | return -ENOMEM; |
792 | 932 | ||
793 | aic32x4->regmap = devm_regmap_init_i2c(i2c, &aic32x4_regmap); | 933 | dev_set_drvdata(dev, aic32x4); |
794 | if (IS_ERR(aic32x4->regmap)) | ||
795 | return PTR_ERR(aic32x4->regmap); | ||
796 | |||
797 | i2c_set_clientdata(i2c, aic32x4); | ||
798 | 934 | ||
799 | if (pdata) { | 935 | if (pdata) { |
800 | aic32x4->power_cfg = pdata->power_cfg; | 936 | aic32x4->power_cfg = pdata->power_cfg; |
@@ -804,7 +940,7 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
804 | } else if (np) { | 940 | } else if (np) { |
805 | ret = aic32x4_parse_dt(aic32x4, np); | 941 | ret = aic32x4_parse_dt(aic32x4, np); |
806 | if (ret) { | 942 | if (ret) { |
807 | dev_err(&i2c->dev, "Failed to parse DT node\n"); | 943 | dev_err(dev, "Failed to parse DT node\n"); |
808 | return ret; | 944 | return ret; |
809 | } | 945 | } |
810 | } else { | 946 | } else { |
@@ -814,71 +950,48 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
814 | aic32x4->rstn_gpio = -1; | 950 | aic32x4->rstn_gpio = -1; |
815 | } | 951 | } |
816 | 952 | ||
817 | aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); | 953 | aic32x4->mclk = devm_clk_get(dev, "mclk"); |
818 | if (IS_ERR(aic32x4->mclk)) { | 954 | if (IS_ERR(aic32x4->mclk)) { |
819 | dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); | 955 | dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); |
820 | return PTR_ERR(aic32x4->mclk); | 956 | return PTR_ERR(aic32x4->mclk); |
821 | } | 957 | } |
822 | 958 | ||
823 | if (gpio_is_valid(aic32x4->rstn_gpio)) { | 959 | if (gpio_is_valid(aic32x4->rstn_gpio)) { |
824 | ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, | 960 | ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio, |
825 | GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); | 961 | GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); |
826 | if (ret != 0) | 962 | if (ret != 0) |
827 | return ret; | 963 | return ret; |
828 | } | 964 | } |
829 | 965 | ||
830 | ret = aic32x4_setup_regulators(&i2c->dev, aic32x4); | 966 | ret = aic32x4_setup_regulators(dev, aic32x4); |
831 | if (ret) { | 967 | if (ret) { |
832 | dev_err(&i2c->dev, "Failed to setup regulators\n"); | 968 | dev_err(dev, "Failed to setup regulators\n"); |
833 | return ret; | 969 | return ret; |
834 | } | 970 | } |
835 | 971 | ||
836 | ret = snd_soc_register_codec(&i2c->dev, | 972 | ret = snd_soc_register_codec(dev, |
837 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); | 973 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); |
838 | if (ret) { | 974 | if (ret) { |
839 | dev_err(&i2c->dev, "Failed to register codec\n"); | 975 | dev_err(dev, "Failed to register codec\n"); |
840 | aic32x4_disable_regulators(aic32x4); | 976 | aic32x4_disable_regulators(aic32x4); |
841 | return ret; | 977 | return ret; |
842 | } | 978 | } |
843 | 979 | ||
844 | i2c_set_clientdata(i2c, aic32x4); | ||
845 | |||
846 | return 0; | 980 | return 0; |
847 | } | 981 | } |
982 | EXPORT_SYMBOL(aic32x4_probe); | ||
848 | 983 | ||
849 | static int aic32x4_i2c_remove(struct i2c_client *client) | 984 | int aic32x4_remove(struct device *dev) |
850 | { | 985 | { |
851 | struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client); | 986 | struct aic32x4_priv *aic32x4 = dev_get_drvdata(dev); |
852 | 987 | ||
853 | aic32x4_disable_regulators(aic32x4); | 988 | aic32x4_disable_regulators(aic32x4); |
854 | 989 | ||
855 | snd_soc_unregister_codec(&client->dev); | 990 | snd_soc_unregister_codec(dev); |
991 | |||
856 | return 0; | 992 | return 0; |
857 | } | 993 | } |
858 | 994 | EXPORT_SYMBOL(aic32x4_remove); | |
859 | static const struct i2c_device_id aic32x4_i2c_id[] = { | ||
860 | { "tlv320aic32x4", 0 }, | ||
861 | { } | ||
862 | }; | ||
863 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); | ||
864 | |||
865 | static const struct of_device_id aic32x4_of_id[] = { | ||
866 | { .compatible = "ti,tlv320aic32x4", }, | ||
867 | { /* senitel */ } | ||
868 | }; | ||
869 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
870 | |||
871 | static struct i2c_driver aic32x4_i2c_driver = { | ||
872 | .driver = { | ||
873 | .name = "tlv320aic32x4", | ||
874 | .of_match_table = aic32x4_of_id, | ||
875 | }, | ||
876 | .probe = aic32x4_i2c_probe, | ||
877 | .remove = aic32x4_i2c_remove, | ||
878 | .id_table = aic32x4_i2c_id, | ||
879 | }; | ||
880 | |||
881 | module_i2c_driver(aic32x4_i2c_driver); | ||
882 | 995 | ||
883 | MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); | 996 | MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); |
884 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); | 997 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); |
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 995f033a855d..a197dd51addc 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h | |||
@@ -10,6 +10,13 @@ | |||
10 | #ifndef _TLV320AIC32X4_H | 10 | #ifndef _TLV320AIC32X4_H |
11 | #define _TLV320AIC32X4_H | 11 | #define _TLV320AIC32X4_H |
12 | 12 | ||
13 | struct device; | ||
14 | struct regmap_config; | ||
15 | |||
16 | extern const struct regmap_config aic32x4_regmap_config; | ||
17 | int aic32x4_probe(struct device *dev, struct regmap *regmap); | ||
18 | int aic32x4_remove(struct device *dev); | ||
19 | |||
13 | /* tlv320aic32x4 register space (in decimal to match datasheet) */ | 20 | /* tlv320aic32x4 register space (in decimal to match datasheet) */ |
14 | 21 | ||
15 | #define AIC32X4_PAGE1 128 | 22 | #define AIC32X4_PAGE1 128 |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index bc3de2e844e6..1f7081043566 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -824,7 +824,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
824 | { | 824 | { |
825 | struct twl6040 *twl6040 = codec->control_data; | 825 | struct twl6040 *twl6040 = codec->control_data; |
826 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 826 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
827 | int ret; | 827 | int ret = 0; |
828 | 828 | ||
829 | switch (level) { | 829 | switch (level) { |
830 | case SND_SOC_BIAS_ON: | 830 | case SND_SOC_BIAS_ON: |
@@ -832,12 +832,16 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
832 | case SND_SOC_BIAS_PREPARE: | 832 | case SND_SOC_BIAS_PREPARE: |
833 | break; | 833 | break; |
834 | case SND_SOC_BIAS_STANDBY: | 834 | case SND_SOC_BIAS_STANDBY: |
835 | if (priv->codec_powered) | 835 | if (priv->codec_powered) { |
836 | /* Select low power PLL in standby */ | ||
837 | ret = twl6040_set_pll(twl6040, TWL6040_SYSCLK_SEL_LPPLL, | ||
838 | 32768, 19200000); | ||
836 | break; | 839 | break; |
840 | } | ||
837 | 841 | ||
838 | ret = twl6040_power(twl6040, 1); | 842 | ret = twl6040_power(twl6040, 1); |
839 | if (ret) | 843 | if (ret) |
840 | return ret; | 844 | break; |
841 | 845 | ||
842 | priv->codec_powered = 1; | 846 | priv->codec_powered = 1; |
843 | 847 | ||
@@ -853,7 +857,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
853 | break; | 857 | break; |
854 | } | 858 | } |
855 | 859 | ||
856 | return 0; | 860 | return ret; |
857 | } | 861 | } |
858 | 862 | ||
859 | static int twl6040_startup(struct snd_pcm_substream *substream, | 863 | static int twl6040_startup(struct snd_pcm_substream *substream, |
@@ -983,9 +987,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i | |||
983 | if (mute) { | 987 | if (mute) { |
984 | /* Power down drivers and DACs */ | 988 | /* Power down drivers and DACs */ |
985 | hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | | 989 | hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | |
986 | TWL6040_HFDRVENA); | 990 | TWL6040_HFDRVENA | TWL6040_HFSWENA); |
987 | hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | | 991 | hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | |
988 | TWL6040_HFDRVENA); | 992 | TWL6040_HFDRVENA | TWL6040_HFSWENA); |
989 | } | 993 | } |
990 | 994 | ||
991 | twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl); | 995 | twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl); |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index a8b3e3f701f9..da60e3fe5ee7 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -1955,11 +1955,16 @@ err_adsp2_codec_probe: | |||
1955 | static int wm5102_codec_remove(struct snd_soc_codec *codec) | 1955 | static int wm5102_codec_remove(struct snd_soc_codec *codec) |
1956 | { | 1956 | { |
1957 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); | 1957 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); |
1958 | struct arizona *arizona = priv->core.arizona; | ||
1958 | 1959 | ||
1959 | wm_adsp2_codec_remove(&priv->core.adsp[0], codec); | 1960 | wm_adsp2_codec_remove(&priv->core.adsp[0], codec); |
1960 | 1961 | ||
1961 | priv->core.arizona->dapm = NULL; | 1962 | priv->core.arizona->dapm = NULL; |
1962 | 1963 | ||
1964 | arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); | ||
1965 | |||
1966 | arizona_free_spk(codec); | ||
1967 | |||
1963 | return 0; | 1968 | return 0; |
1964 | } | 1969 | } |
1965 | 1970 | ||
@@ -2093,10 +2098,14 @@ static int wm5102_probe(struct platform_device *pdev) | |||
2093 | 2098 | ||
2094 | static int wm5102_remove(struct platform_device *pdev) | 2099 | static int wm5102_remove(struct platform_device *pdev) |
2095 | { | 2100 | { |
2101 | struct wm5102_priv *wm5102 = platform_get_drvdata(pdev); | ||
2102 | |||
2096 | snd_soc_unregister_platform(&pdev->dev); | 2103 | snd_soc_unregister_platform(&pdev->dev); |
2097 | snd_soc_unregister_codec(&pdev->dev); | 2104 | snd_soc_unregister_codec(&pdev->dev); |
2098 | pm_runtime_disable(&pdev->dev); | 2105 | pm_runtime_disable(&pdev->dev); |
2099 | 2106 | ||
2107 | wm_adsp2_remove(&wm5102->core.adsp[0]); | ||
2108 | |||
2100 | return 0; | 2109 | return 0; |
2101 | } | 2110 | } |
2102 | 2111 | ||
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 83ba70fe16e6..b5820e4d5471 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -2298,6 +2298,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) | |||
2298 | 2298 | ||
2299 | arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); | 2299 | arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); |
2300 | 2300 | ||
2301 | arizona_free_spk(codec); | ||
2302 | |||
2301 | return 0; | 2303 | return 0; |
2302 | } | 2304 | } |
2303 | 2305 | ||
@@ -2435,10 +2437,16 @@ static int wm5110_probe(struct platform_device *pdev) | |||
2435 | 2437 | ||
2436 | static int wm5110_remove(struct platform_device *pdev) | 2438 | static int wm5110_remove(struct platform_device *pdev) |
2437 | { | 2439 | { |
2440 | struct wm5110_priv *wm5110 = platform_get_drvdata(pdev); | ||
2441 | int i; | ||
2442 | |||
2438 | snd_soc_unregister_platform(&pdev->dev); | 2443 | snd_soc_unregister_platform(&pdev->dev); |
2439 | snd_soc_unregister_codec(&pdev->dev); | 2444 | snd_soc_unregister_codec(&pdev->dev); |
2440 | pm_runtime_disable(&pdev->dev); | 2445 | pm_runtime_disable(&pdev->dev); |
2441 | 2446 | ||
2447 | for (i = 0; i < WM5110_NUM_ADSP; i++) | ||
2448 | wm_adsp2_remove(&wm5110->core.adsp[i]); | ||
2449 | |||
2442 | return 0; | 2450 | return 0; |
2443 | } | 2451 | } |
2444 | 2452 | ||
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 88223608a33f..720a14e0687d 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -2471,7 +2471,7 @@ static void wm8962_configure_bclk(struct snd_soc_codec *codec) | |||
2471 | break; | 2471 | break; |
2472 | default: | 2472 | default: |
2473 | dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n"); | 2473 | dev_warn(codec->dev, "Unknown DSPCLK divisor read back\n"); |
2474 | dspclk = wm8962->sysclk; | 2474 | dspclk = wm8962->sysclk_rate; |
2475 | } | 2475 | } |
2476 | 2476 | ||
2477 | dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk); | 2477 | dev_dbg(codec->dev, "DSPCLK is %dHz, BCLK %d\n", dspclk, wm8962->bclk); |
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 52d766efe14f..6b0785b5a5c5 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c | |||
@@ -1072,6 +1072,8 @@ static int wm8997_codec_remove(struct snd_soc_codec *codec) | |||
1072 | 1072 | ||
1073 | priv->core.arizona->dapm = NULL; | 1073 | priv->core.arizona->dapm = NULL; |
1074 | 1074 | ||
1075 | arizona_free_spk(codec); | ||
1076 | |||
1075 | return 0; | 1077 | return 0; |
1076 | } | 1078 | } |
1077 | 1079 | ||
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 012396074a8a..449f66636205 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c | |||
@@ -1324,6 +1324,8 @@ static int wm8998_codec_remove(struct snd_soc_codec *codec) | |||
1324 | 1324 | ||
1325 | priv->core.arizona->dapm = NULL; | 1325 | priv->core.arizona->dapm = NULL; |
1326 | 1326 | ||
1327 | arizona_free_spk(codec); | ||
1328 | |||
1327 | return 0; | 1329 | return 0; |
1328 | } | 1330 | } |
1329 | 1331 | ||
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d3b1cb15e7f0..a07bd7c2c587 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -160,6 +160,8 @@ | |||
160 | #define ADSP2_RAM_RDY_SHIFT 0 | 160 | #define ADSP2_RAM_RDY_SHIFT 0 |
161 | #define ADSP2_RAM_RDY_WIDTH 1 | 161 | #define ADSP2_RAM_RDY_WIDTH 1 |
162 | 162 | ||
163 | #define ADSP_MAX_STD_CTRL_SIZE 512 | ||
164 | |||
163 | struct wm_adsp_buf { | 165 | struct wm_adsp_buf { |
164 | struct list_head list; | 166 | struct list_head list; |
165 | void *buf; | 167 | void *buf; |
@@ -271,8 +273,11 @@ struct wm_adsp_buffer { | |||
271 | __be32 words_written[2]; /* total words written (64 bit) */ | 273 | __be32 words_written[2]; /* total words written (64 bit) */ |
272 | }; | 274 | }; |
273 | 275 | ||
276 | struct wm_adsp_compr; | ||
277 | |||
274 | struct wm_adsp_compr_buf { | 278 | struct wm_adsp_compr_buf { |
275 | struct wm_adsp *dsp; | 279 | struct wm_adsp *dsp; |
280 | struct wm_adsp_compr *compr; | ||
276 | 281 | ||
277 | struct wm_adsp_buffer_region *regions; | 282 | struct wm_adsp_buffer_region *regions; |
278 | u32 host_buf_ptr; | 283 | u32 host_buf_ptr; |
@@ -435,6 +440,7 @@ struct wm_coeff_ctl { | |||
435 | size_t len; | 440 | size_t len; |
436 | unsigned int set:1; | 441 | unsigned int set:1; |
437 | struct snd_kcontrol *kcontrol; | 442 | struct snd_kcontrol *kcontrol; |
443 | struct soc_bytes_ext bytes_ext; | ||
438 | unsigned int flags; | 444 | unsigned int flags; |
439 | }; | 445 | }; |
440 | 446 | ||
@@ -711,10 +717,17 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) | |||
711 | be16_to_cpu(scratch[3])); | 717 | be16_to_cpu(scratch[3])); |
712 | } | 718 | } |
713 | 719 | ||
720 | static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) | ||
721 | { | ||
722 | return container_of(ext, struct wm_coeff_ctl, bytes_ext); | ||
723 | } | ||
724 | |||
714 | static int wm_coeff_info(struct snd_kcontrol *kctl, | 725 | static int wm_coeff_info(struct snd_kcontrol *kctl, |
715 | struct snd_ctl_elem_info *uinfo) | 726 | struct snd_ctl_elem_info *uinfo) |
716 | { | 727 | { |
717 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; | 728 | struct soc_bytes_ext *bytes_ext = |
729 | (struct soc_bytes_ext *)kctl->private_value; | ||
730 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
718 | 731 | ||
719 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | 732 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; |
720 | uinfo->count = ctl->len; | 733 | uinfo->count = ctl->len; |
@@ -763,7 +776,9 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, | |||
763 | static int wm_coeff_put(struct snd_kcontrol *kctl, | 776 | static int wm_coeff_put(struct snd_kcontrol *kctl, |
764 | struct snd_ctl_elem_value *ucontrol) | 777 | struct snd_ctl_elem_value *ucontrol) |
765 | { | 778 | { |
766 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; | 779 | struct soc_bytes_ext *bytes_ext = |
780 | (struct soc_bytes_ext *)kctl->private_value; | ||
781 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
767 | char *p = ucontrol->value.bytes.data; | 782 | char *p = ucontrol->value.bytes.data; |
768 | int ret = 0; | 783 | int ret = 0; |
769 | 784 | ||
@@ -780,6 +795,29 @@ static int wm_coeff_put(struct snd_kcontrol *kctl, | |||
780 | return ret; | 795 | return ret; |
781 | } | 796 | } |
782 | 797 | ||
798 | static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, | ||
799 | const unsigned int __user *bytes, unsigned int size) | ||
800 | { | ||
801 | struct soc_bytes_ext *bytes_ext = | ||
802 | (struct soc_bytes_ext *)kctl->private_value; | ||
803 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
804 | int ret = 0; | ||
805 | |||
806 | mutex_lock(&ctl->dsp->pwr_lock); | ||
807 | |||
808 | if (copy_from_user(ctl->cache, bytes, size)) { | ||
809 | ret = -EFAULT; | ||
810 | } else { | ||
811 | ctl->set = 1; | ||
812 | if (ctl->enabled) | ||
813 | ret = wm_coeff_write_control(ctl, ctl->cache, size); | ||
814 | } | ||
815 | |||
816 | mutex_unlock(&ctl->dsp->pwr_lock); | ||
817 | |||
818 | return ret; | ||
819 | } | ||
820 | |||
783 | static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, | 821 | static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, |
784 | void *buf, size_t len) | 822 | void *buf, size_t len) |
785 | { | 823 | { |
@@ -822,7 +860,9 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, | |||
822 | static int wm_coeff_get(struct snd_kcontrol *kctl, | 860 | static int wm_coeff_get(struct snd_kcontrol *kctl, |
823 | struct snd_ctl_elem_value *ucontrol) | 861 | struct snd_ctl_elem_value *ucontrol) |
824 | { | 862 | { |
825 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; | 863 | struct soc_bytes_ext *bytes_ext = |
864 | (struct soc_bytes_ext *)kctl->private_value; | ||
865 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
826 | char *p = ucontrol->value.bytes.data; | 866 | char *p = ucontrol->value.bytes.data; |
827 | int ret = 0; | 867 | int ret = 0; |
828 | 868 | ||
@@ -845,12 +885,72 @@ static int wm_coeff_get(struct snd_kcontrol *kctl, | |||
845 | return ret; | 885 | return ret; |
846 | } | 886 | } |
847 | 887 | ||
888 | static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, | ||
889 | unsigned int __user *bytes, unsigned int size) | ||
890 | { | ||
891 | struct soc_bytes_ext *bytes_ext = | ||
892 | (struct soc_bytes_ext *)kctl->private_value; | ||
893 | struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); | ||
894 | int ret = 0; | ||
895 | |||
896 | mutex_lock(&ctl->dsp->pwr_lock); | ||
897 | |||
898 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { | ||
899 | if (ctl->enabled) | ||
900 | ret = wm_coeff_read_control(ctl, ctl->cache, size); | ||
901 | else | ||
902 | ret = -EPERM; | ||
903 | } else { | ||
904 | if (!ctl->flags && ctl->enabled) | ||
905 | ret = wm_coeff_read_control(ctl, ctl->cache, size); | ||
906 | } | ||
907 | |||
908 | if (!ret && copy_to_user(bytes, ctl->cache, size)) | ||
909 | ret = -EFAULT; | ||
910 | |||
911 | mutex_unlock(&ctl->dsp->pwr_lock); | ||
912 | |||
913 | return ret; | ||
914 | } | ||
915 | |||
848 | struct wmfw_ctl_work { | 916 | struct wmfw_ctl_work { |
849 | struct wm_adsp *dsp; | 917 | struct wm_adsp *dsp; |
850 | struct wm_coeff_ctl *ctl; | 918 | struct wm_coeff_ctl *ctl; |
851 | struct work_struct work; | 919 | struct work_struct work; |
852 | }; | 920 | }; |
853 | 921 | ||
922 | static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) | ||
923 | { | ||
924 | unsigned int out, rd, wr, vol; | ||
925 | |||
926 | if (len > ADSP_MAX_STD_CTRL_SIZE) { | ||
927 | rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ; | ||
928 | wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE; | ||
929 | vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
930 | |||
931 | out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | ||
932 | } else { | ||
933 | rd = SNDRV_CTL_ELEM_ACCESS_READ; | ||
934 | wr = SNDRV_CTL_ELEM_ACCESS_WRITE; | ||
935 | vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
936 | |||
937 | out = 0; | ||
938 | } | ||
939 | |||
940 | if (in) { | ||
941 | if (in & WMFW_CTL_FLAG_READABLE) | ||
942 | out |= rd; | ||
943 | if (in & WMFW_CTL_FLAG_WRITEABLE) | ||
944 | out |= wr; | ||
945 | if (in & WMFW_CTL_FLAG_VOLATILE) | ||
946 | out |= vol; | ||
947 | } else { | ||
948 | out |= rd | wr | vol; | ||
949 | } | ||
950 | |||
951 | return out; | ||
952 | } | ||
953 | |||
854 | static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) | 954 | static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) |
855 | { | 955 | { |
856 | struct snd_kcontrol_new *kcontrol; | 956 | struct snd_kcontrol_new *kcontrol; |
@@ -868,19 +968,15 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) | |||
868 | kcontrol->info = wm_coeff_info; | 968 | kcontrol->info = wm_coeff_info; |
869 | kcontrol->get = wm_coeff_get; | 969 | kcontrol->get = wm_coeff_get; |
870 | kcontrol->put = wm_coeff_put; | 970 | kcontrol->put = wm_coeff_put; |
871 | kcontrol->private_value = (unsigned long)ctl; | 971 | kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
972 | kcontrol->tlv.c = snd_soc_bytes_tlv_callback; | ||
973 | kcontrol->private_value = (unsigned long)&ctl->bytes_ext; | ||
872 | 974 | ||
873 | if (ctl->flags) { | 975 | ctl->bytes_ext.max = ctl->len; |
874 | if (ctl->flags & WMFW_CTL_FLAG_WRITEABLE) | 976 | ctl->bytes_ext.get = wm_coeff_tlv_get; |
875 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_WRITE; | 977 | ctl->bytes_ext.put = wm_coeff_tlv_put; |
876 | if (ctl->flags & WMFW_CTL_FLAG_READABLE) | 978 | |
877 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_READ; | 979 | kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); |
878 | if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) | ||
879 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
880 | } else { | ||
881 | kcontrol->access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
882 | kcontrol->access |= SNDRV_CTL_ELEM_ACCESS_VOLATILE; | ||
883 | } | ||
884 | 980 | ||
885 | ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); | 981 | ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); |
886 | if (ret < 0) | 982 | if (ret < 0) |
@@ -944,6 +1040,13 @@ static void wm_adsp_ctl_work(struct work_struct *work) | |||
944 | kfree(ctl_work); | 1040 | kfree(ctl_work); |
945 | } | 1041 | } |
946 | 1042 | ||
1043 | static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl) | ||
1044 | { | ||
1045 | kfree(ctl->cache); | ||
1046 | kfree(ctl->name); | ||
1047 | kfree(ctl); | ||
1048 | } | ||
1049 | |||
947 | static int wm_adsp_create_control(struct wm_adsp *dsp, | 1050 | static int wm_adsp_create_control(struct wm_adsp *dsp, |
948 | const struct wm_adsp_alg_region *alg_region, | 1051 | const struct wm_adsp_alg_region *alg_region, |
949 | unsigned int offset, unsigned int len, | 1052 | unsigned int offset, unsigned int len, |
@@ -1032,11 +1135,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, | |||
1032 | 1135 | ||
1033 | ctl->flags = flags; | 1136 | ctl->flags = flags; |
1034 | ctl->offset = offset; | 1137 | ctl->offset = offset; |
1035 | if (len > 512) { | ||
1036 | adsp_warn(dsp, "Truncating control %s from %d\n", | ||
1037 | ctl->name, len); | ||
1038 | len = 512; | ||
1039 | } | ||
1040 | ctl->len = len; | 1138 | ctl->len = len; |
1041 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); | 1139 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); |
1042 | if (!ctl->cache) { | 1140 | if (!ctl->cache) { |
@@ -1564,6 +1662,19 @@ static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, | |||
1564 | return alg_region; | 1662 | return alg_region; |
1565 | } | 1663 | } |
1566 | 1664 | ||
1665 | static void wm_adsp_free_alg_regions(struct wm_adsp *dsp) | ||
1666 | { | ||
1667 | struct wm_adsp_alg_region *alg_region; | ||
1668 | |||
1669 | while (!list_empty(&dsp->alg_regions)) { | ||
1670 | alg_region = list_first_entry(&dsp->alg_regions, | ||
1671 | struct wm_adsp_alg_region, | ||
1672 | list); | ||
1673 | list_del(&alg_region->list); | ||
1674 | kfree(alg_region); | ||
1675 | } | ||
1676 | } | ||
1677 | |||
1567 | static int wm_adsp1_setup_algs(struct wm_adsp *dsp) | 1678 | static int wm_adsp1_setup_algs(struct wm_adsp *dsp) |
1568 | { | 1679 | { |
1569 | struct wmfw_adsp1_id_hdr adsp1_id; | 1680 | struct wmfw_adsp1_id_hdr adsp1_id; |
@@ -1994,7 +2105,6 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1994 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 2105 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
1995 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 2106 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
1996 | struct wm_adsp *dsp = &dsps[w->shift]; | 2107 | struct wm_adsp *dsp = &dsps[w->shift]; |
1997 | struct wm_adsp_alg_region *alg_region; | ||
1998 | struct wm_coeff_ctl *ctl; | 2108 | struct wm_coeff_ctl *ctl; |
1999 | int ret; | 2109 | int ret; |
2000 | unsigned int val; | 2110 | unsigned int val; |
@@ -2074,13 +2184,8 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
2074 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2184 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
2075 | ctl->enabled = 0; | 2185 | ctl->enabled = 0; |
2076 | 2186 | ||
2077 | while (!list_empty(&dsp->alg_regions)) { | 2187 | |
2078 | alg_region = list_first_entry(&dsp->alg_regions, | 2188 | wm_adsp_free_alg_regions(dsp); |
2079 | struct wm_adsp_alg_region, | ||
2080 | list); | ||
2081 | list_del(&alg_region->list); | ||
2082 | kfree(alg_region); | ||
2083 | } | ||
2084 | break; | 2189 | break; |
2085 | 2190 | ||
2086 | default: | 2191 | default: |
@@ -2222,7 +2327,6 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
2222 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 2327 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
2223 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 2328 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
2224 | struct wm_adsp *dsp = &dsps[w->shift]; | 2329 | struct wm_adsp *dsp = &dsps[w->shift]; |
2225 | struct wm_adsp_alg_region *alg_region; | ||
2226 | struct wm_coeff_ctl *ctl; | 2330 | struct wm_coeff_ctl *ctl; |
2227 | int ret; | 2331 | int ret; |
2228 | 2332 | ||
@@ -2240,9 +2344,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
2240 | if (ret != 0) | 2344 | if (ret != 0) |
2241 | goto err; | 2345 | goto err; |
2242 | 2346 | ||
2347 | mutex_lock(&dsp->pwr_lock); | ||
2348 | |||
2243 | if (wm_adsp_fw[dsp->fw].num_caps != 0) | 2349 | if (wm_adsp_fw[dsp->fw].num_caps != 0) |
2244 | ret = wm_adsp_buffer_init(dsp); | 2350 | ret = wm_adsp_buffer_init(dsp); |
2245 | 2351 | ||
2352 | mutex_unlock(&dsp->pwr_lock); | ||
2353 | |||
2246 | break; | 2354 | break; |
2247 | 2355 | ||
2248 | case SND_SOC_DAPM_PRE_PMD: | 2356 | case SND_SOC_DAPM_PRE_PMD: |
@@ -2269,13 +2377,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
2269 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2377 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
2270 | ctl->enabled = 0; | 2378 | ctl->enabled = 0; |
2271 | 2379 | ||
2272 | while (!list_empty(&dsp->alg_regions)) { | 2380 | wm_adsp_free_alg_regions(dsp); |
2273 | alg_region = list_first_entry(&dsp->alg_regions, | ||
2274 | struct wm_adsp_alg_region, | ||
2275 | list); | ||
2276 | list_del(&alg_region->list); | ||
2277 | kfree(alg_region); | ||
2278 | } | ||
2279 | 2381 | ||
2280 | if (wm_adsp_fw[dsp->fw].num_caps != 0) | 2382 | if (wm_adsp_fw[dsp->fw].num_caps != 0) |
2281 | wm_adsp_buffer_free(dsp); | 2383 | wm_adsp_buffer_free(dsp); |
@@ -2340,6 +2442,54 @@ int wm_adsp2_init(struct wm_adsp *dsp) | |||
2340 | } | 2442 | } |
2341 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 2443 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
2342 | 2444 | ||
2445 | void wm_adsp2_remove(struct wm_adsp *dsp) | ||
2446 | { | ||
2447 | struct wm_coeff_ctl *ctl; | ||
2448 | |||
2449 | while (!list_empty(&dsp->ctl_list)) { | ||
2450 | ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl, | ||
2451 | list); | ||
2452 | list_del(&ctl->list); | ||
2453 | wm_adsp_free_ctl_blk(ctl); | ||
2454 | } | ||
2455 | } | ||
2456 | EXPORT_SYMBOL_GPL(wm_adsp2_remove); | ||
2457 | |||
2458 | static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) | ||
2459 | { | ||
2460 | return compr->buf != NULL; | ||
2461 | } | ||
2462 | |||
2463 | static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) | ||
2464 | { | ||
2465 | /* | ||
2466 | * Note this will be more complex once each DSP can support multiple | ||
2467 | * streams | ||
2468 | */ | ||
2469 | if (!compr->dsp->buffer) | ||
2470 | return -EINVAL; | ||
2471 | |||
2472 | compr->buf = compr->dsp->buffer; | ||
2473 | compr->buf->compr = compr; | ||
2474 | |||
2475 | return 0; | ||
2476 | } | ||
2477 | |||
2478 | static void wm_adsp_compr_detach(struct wm_adsp_compr *compr) | ||
2479 | { | ||
2480 | if (!compr) | ||
2481 | return; | ||
2482 | |||
2483 | /* Wake the poll so it can see buffer is no longer attached */ | ||
2484 | if (compr->stream) | ||
2485 | snd_compr_fragment_elapsed(compr->stream); | ||
2486 | |||
2487 | if (wm_adsp_compr_attached(compr)) { | ||
2488 | compr->buf->compr = NULL; | ||
2489 | compr->buf = NULL; | ||
2490 | } | ||
2491 | } | ||
2492 | |||
2343 | int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) | 2493 | int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) |
2344 | { | 2494 | { |
2345 | struct wm_adsp_compr *compr; | 2495 | struct wm_adsp_compr *compr; |
@@ -2393,6 +2543,7 @@ int wm_adsp_compr_free(struct snd_compr_stream *stream) | |||
2393 | 2543 | ||
2394 | mutex_lock(&dsp->pwr_lock); | 2544 | mutex_lock(&dsp->pwr_lock); |
2395 | 2545 | ||
2546 | wm_adsp_compr_detach(compr); | ||
2396 | dsp->compr = NULL; | 2547 | dsp->compr = NULL; |
2397 | 2548 | ||
2398 | kfree(compr->raw_buf); | 2549 | kfree(compr->raw_buf); |
@@ -2689,6 +2840,8 @@ err_buffer: | |||
2689 | static int wm_adsp_buffer_free(struct wm_adsp *dsp) | 2840 | static int wm_adsp_buffer_free(struct wm_adsp *dsp) |
2690 | { | 2841 | { |
2691 | if (dsp->buffer) { | 2842 | if (dsp->buffer) { |
2843 | wm_adsp_compr_detach(dsp->buffer->compr); | ||
2844 | |||
2692 | kfree(dsp->buffer->regions); | 2845 | kfree(dsp->buffer->regions); |
2693 | kfree(dsp->buffer); | 2846 | kfree(dsp->buffer); |
2694 | 2847 | ||
@@ -2698,25 +2851,6 @@ static int wm_adsp_buffer_free(struct wm_adsp *dsp) | |||
2698 | return 0; | 2851 | return 0; |
2699 | } | 2852 | } |
2700 | 2853 | ||
2701 | static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) | ||
2702 | { | ||
2703 | return compr->buf != NULL; | ||
2704 | } | ||
2705 | |||
2706 | static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) | ||
2707 | { | ||
2708 | /* | ||
2709 | * Note this will be more complex once each DSP can support multiple | ||
2710 | * streams | ||
2711 | */ | ||
2712 | if (!compr->dsp->buffer) | ||
2713 | return -EINVAL; | ||
2714 | |||
2715 | compr->buf = compr->dsp->buffer; | ||
2716 | |||
2717 | return 0; | ||
2718 | } | ||
2719 | |||
2720 | int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) | 2854 | int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) |
2721 | { | 2855 | { |
2722 | struct wm_adsp_compr *compr = stream->runtime->private_data; | 2856 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
@@ -2805,21 +2939,41 @@ static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) | |||
2805 | avail += wm_adsp_buffer_size(buf); | 2939 | avail += wm_adsp_buffer_size(buf); |
2806 | 2940 | ||
2807 | adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", | 2941 | adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", |
2808 | buf->read_index, write_index, avail); | 2942 | buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); |
2809 | 2943 | ||
2810 | buf->avail = avail; | 2944 | buf->avail = avail; |
2811 | 2945 | ||
2812 | return 0; | 2946 | return 0; |
2813 | } | 2947 | } |
2814 | 2948 | ||
2949 | static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) | ||
2950 | { | ||
2951 | int ret; | ||
2952 | |||
2953 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); | ||
2954 | if (ret < 0) { | ||
2955 | adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); | ||
2956 | return ret; | ||
2957 | } | ||
2958 | if (buf->error != 0) { | ||
2959 | adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); | ||
2960 | return -EIO; | ||
2961 | } | ||
2962 | |||
2963 | return 0; | ||
2964 | } | ||
2965 | |||
2815 | int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | 2966 | int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) |
2816 | { | 2967 | { |
2817 | struct wm_adsp_compr_buf *buf = dsp->buffer; | 2968 | struct wm_adsp_compr_buf *buf; |
2818 | struct wm_adsp_compr *compr = dsp->compr; | 2969 | struct wm_adsp_compr *compr; |
2819 | int ret = 0; | 2970 | int ret = 0; |
2820 | 2971 | ||
2821 | mutex_lock(&dsp->pwr_lock); | 2972 | mutex_lock(&dsp->pwr_lock); |
2822 | 2973 | ||
2974 | buf = dsp->buffer; | ||
2975 | compr = dsp->compr; | ||
2976 | |||
2823 | if (!buf) { | 2977 | if (!buf) { |
2824 | ret = -ENODEV; | 2978 | ret = -ENODEV; |
2825 | goto out; | 2979 | goto out; |
@@ -2827,16 +2981,9 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | |||
2827 | 2981 | ||
2828 | adsp_dbg(dsp, "Handling buffer IRQ\n"); | 2982 | adsp_dbg(dsp, "Handling buffer IRQ\n"); |
2829 | 2983 | ||
2830 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); | 2984 | ret = wm_adsp_buffer_get_error(buf); |
2831 | if (ret < 0) { | 2985 | if (ret < 0) |
2832 | adsp_err(dsp, "Failed to check buffer error: %d\n", ret); | 2986 | goto out_notify; /* Wake poll to report error */ |
2833 | goto out; | ||
2834 | } | ||
2835 | if (buf->error != 0) { | ||
2836 | adsp_err(dsp, "Buffer error occurred: %d\n", buf->error); | ||
2837 | ret = -EIO; | ||
2838 | goto out; | ||
2839 | } | ||
2840 | 2987 | ||
2841 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), | 2988 | ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), |
2842 | &buf->irq_count); | 2989 | &buf->irq_count); |
@@ -2851,6 +2998,7 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | |||
2851 | goto out; | 2998 | goto out; |
2852 | } | 2999 | } |
2853 | 3000 | ||
3001 | out_notify: | ||
2854 | if (compr && compr->stream) | 3002 | if (compr && compr->stream) |
2855 | snd_compr_fragment_elapsed(compr->stream); | 3003 | snd_compr_fragment_elapsed(compr->stream); |
2856 | 3004 | ||
@@ -2879,14 +3027,16 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
2879 | struct snd_compr_tstamp *tstamp) | 3027 | struct snd_compr_tstamp *tstamp) |
2880 | { | 3028 | { |
2881 | struct wm_adsp_compr *compr = stream->runtime->private_data; | 3029 | struct wm_adsp_compr *compr = stream->runtime->private_data; |
2882 | struct wm_adsp_compr_buf *buf = compr->buf; | ||
2883 | struct wm_adsp *dsp = compr->dsp; | 3030 | struct wm_adsp *dsp = compr->dsp; |
3031 | struct wm_adsp_compr_buf *buf; | ||
2884 | int ret = 0; | 3032 | int ret = 0; |
2885 | 3033 | ||
2886 | adsp_dbg(dsp, "Pointer request\n"); | 3034 | adsp_dbg(dsp, "Pointer request\n"); |
2887 | 3035 | ||
2888 | mutex_lock(&dsp->pwr_lock); | 3036 | mutex_lock(&dsp->pwr_lock); |
2889 | 3037 | ||
3038 | buf = compr->buf; | ||
3039 | |||
2890 | if (!compr->buf) { | 3040 | if (!compr->buf) { |
2891 | ret = -ENXIO; | 3041 | ret = -ENXIO; |
2892 | goto out; | 3042 | goto out; |
@@ -2909,6 +3059,10 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
2909 | * DSP to inform us once a whole fragment is available. | 3059 | * DSP to inform us once a whole fragment is available. |
2910 | */ | 3060 | */ |
2911 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { | 3061 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { |
3062 | ret = wm_adsp_buffer_get_error(buf); | ||
3063 | if (ret < 0) | ||
3064 | goto out; | ||
3065 | |||
2912 | ret = wm_adsp_buffer_reenable_irq(buf); | 3066 | ret = wm_adsp_buffer_reenable_irq(buf); |
2913 | if (ret < 0) { | 3067 | if (ret < 0) { |
2914 | adsp_err(dsp, | 3068 | adsp_err(dsp, |
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index b61cb57e600f..feb61e2c4bb4 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
@@ -92,6 +92,7 @@ extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; | |||
92 | 92 | ||
93 | int wm_adsp1_init(struct wm_adsp *dsp); | 93 | int wm_adsp1_init(struct wm_adsp *dsp); |
94 | int wm_adsp2_init(struct wm_adsp *dsp); | 94 | int wm_adsp2_init(struct wm_adsp *dsp); |
95 | void wm_adsp2_remove(struct wm_adsp *dsp); | ||
95 | int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); | 96 | int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); |
96 | int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); | 97 | int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); |
97 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, | 98 | int wm_adsp1_event(struct snd_soc_dapm_widget *w, |
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 50ca291cc225..6b732d8e5896 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -16,7 +16,11 @@ config SND_EDMA_SOC | |||
16 | - DRA7xx family | 16 | - DRA7xx family |
17 | 17 | ||
18 | config SND_DAVINCI_SOC_I2S | 18 | config SND_DAVINCI_SOC_I2S |
19 | tristate | 19 | tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support" |
20 | depends on SND_EDMA_SOC | ||
21 | help | ||
22 | Say Y or M here if you want to have support for McBSP IP found in | ||
23 | Texas Instruments DaVinci DA850 SoCs. | ||
20 | 24 | ||
21 | config SND_DAVINCI_SOC_MCASP | 25 | config SND_DAVINCI_SOC_MCASP |
22 | tristate "Multichannel Audio Serial Port (McASP) support" | 26 | tristate "Multichannel Audio Serial Port (McASP) support" |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index ec98548a5fc9..384961651904 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -4,9 +4,15 @@ | |||
4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> | 4 | * Author: Vladimir Barinov, <vbarinov@embeddedalley.com> |
5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> | 5 | * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.com> |
6 | * | 6 | * |
7 | * DT support (c) 2016 Petr Kulhavy, Barix AG <petr@barix.com> | ||
8 | * based on davinci-mcasp.c DT support | ||
9 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 11 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | * | ||
14 | * TODO: | ||
15 | * on DA850 implement HW FIFOs instead of DMA into DXR and DRR registers | ||
10 | */ | 16 | */ |
11 | 17 | ||
12 | #include <linux/init.h> | 18 | #include <linux/init.h> |
@@ -650,13 +656,24 @@ static const struct snd_soc_component_driver davinci_i2s_component = { | |||
650 | 656 | ||
651 | static int davinci_i2s_probe(struct platform_device *pdev) | 657 | static int davinci_i2s_probe(struct platform_device *pdev) |
652 | { | 658 | { |
659 | struct snd_dmaengine_dai_dma_data *dma_data; | ||
653 | struct davinci_mcbsp_dev *dev; | 660 | struct davinci_mcbsp_dev *dev; |
654 | struct resource *mem, *res; | 661 | struct resource *mem, *res; |
655 | void __iomem *io_base; | 662 | void __iomem *io_base; |
656 | int *dma; | 663 | int *dma; |
657 | int ret; | 664 | int ret; |
658 | 665 | ||
659 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 666 | mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); |
667 | if (!mem) { | ||
668 | dev_warn(&pdev->dev, | ||
669 | "\"mpu\" mem resource not found, using index 0\n"); | ||
670 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
671 | if (!mem) { | ||
672 | dev_err(&pdev->dev, "no mem resource?\n"); | ||
673 | return -ENODEV; | ||
674 | } | ||
675 | } | ||
676 | |||
660 | io_base = devm_ioremap_resource(&pdev->dev, mem); | 677 | io_base = devm_ioremap_resource(&pdev->dev, mem); |
661 | if (IS_ERR(io_base)) | 678 | if (IS_ERR(io_base)) |
662 | return PTR_ERR(io_base); | 679 | return PTR_ERR(io_base); |
@@ -666,39 +683,43 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
666 | if (!dev) | 683 | if (!dev) |
667 | return -ENOMEM; | 684 | return -ENOMEM; |
668 | 685 | ||
669 | dev->clk = clk_get(&pdev->dev, NULL); | ||
670 | if (IS_ERR(dev->clk)) | ||
671 | return -ENODEV; | ||
672 | clk_enable(dev->clk); | ||
673 | |||
674 | dev->base = io_base; | 686 | dev->base = io_base; |
675 | 687 | ||
676 | dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = | 688 | /* setup DMA, first TX, then RX */ |
677 | (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); | 689 | dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; |
690 | dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); | ||
678 | 691 | ||
679 | dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = | ||
680 | (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); | ||
681 | |||
682 | /* first TX, then RX */ | ||
683 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 692 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
684 | if (!res) { | 693 | if (res) { |
685 | dev_err(&pdev->dev, "no DMA resource\n"); | 694 | dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; |
686 | ret = -ENXIO; | 695 | *dma = res->start; |
687 | goto err_release_clk; | 696 | dma_data->filter_data = dma; |
697 | } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { | ||
698 | dma_data->filter_data = "tx"; | ||
699 | } else { | ||
700 | dev_err(&pdev->dev, "Missing DMA tx resource\n"); | ||
701 | return -ENODEV; | ||
688 | } | 702 | } |
689 | dma = &dev->dma_request[SNDRV_PCM_STREAM_PLAYBACK]; | 703 | |
690 | *dma = res->start; | 704 | dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; |
691 | dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = dma; | 705 | dma_data->addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); |
692 | 706 | ||
693 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 707 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
694 | if (!res) { | 708 | if (res) { |
695 | dev_err(&pdev->dev, "no DMA resource\n"); | 709 | dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; |
696 | ret = -ENXIO; | 710 | *dma = res->start; |
697 | goto err_release_clk; | 711 | dma_data->filter_data = dma; |
712 | } else if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { | ||
713 | dma_data->filter_data = "rx"; | ||
714 | } else { | ||
715 | dev_err(&pdev->dev, "Missing DMA rx resource\n"); | ||
716 | return -ENODEV; | ||
698 | } | 717 | } |
699 | dma = &dev->dma_request[SNDRV_PCM_STREAM_CAPTURE]; | 718 | |
700 | *dma = res->start; | 719 | dev->clk = clk_get(&pdev->dev, NULL); |
701 | dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = dma; | 720 | if (IS_ERR(dev->clk)) |
721 | return -ENODEV; | ||
722 | clk_enable(dev->clk); | ||
702 | 723 | ||
703 | dev->dev = &pdev->dev; | 724 | dev->dev = &pdev->dev; |
704 | dev_set_drvdata(&pdev->dev, dev); | 725 | dev_set_drvdata(&pdev->dev, dev); |
@@ -737,11 +758,18 @@ static int davinci_i2s_remove(struct platform_device *pdev) | |||
737 | return 0; | 758 | return 0; |
738 | } | 759 | } |
739 | 760 | ||
761 | static const struct of_device_id davinci_i2s_match[] = { | ||
762 | { .compatible = "ti,da850-mcbsp" }, | ||
763 | {}, | ||
764 | }; | ||
765 | MODULE_DEVICE_TABLE(of, davinci_i2s_match); | ||
766 | |||
740 | static struct platform_driver davinci_mcbsp_driver = { | 767 | static struct platform_driver davinci_mcbsp_driver = { |
741 | .probe = davinci_i2s_probe, | 768 | .probe = davinci_i2s_probe, |
742 | .remove = davinci_i2s_remove, | 769 | .remove = davinci_i2s_remove, |
743 | .driver = { | 770 | .driver = { |
744 | .name = "davinci-mcbsp", | 771 | .name = "davinci-mcbsp", |
772 | .of_match_table = of_match_ptr(davinci_i2s_match), | ||
745 | }, | 773 | }, |
746 | }; | 774 | }; |
747 | 775 | ||
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index e1324989bd6b..0f66fda2c772 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -489,7 +489,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
489 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); | 489 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, AFSRE); |
490 | 490 | ||
491 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, | 491 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, |
492 | ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); | 492 | ACLKX | AFSX | ACLKR | AHCLKR | AFSR); |
493 | mcasp->bclk_master = 0; | 493 | mcasp->bclk_master = 0; |
494 | break; | 494 | break; |
495 | default: | 495 | default: |
@@ -540,21 +540,19 @@ out: | |||
540 | return ret; | 540 | return ret; |
541 | } | 541 | } |
542 | 542 | ||
543 | static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, | 543 | static int __davinci_mcasp_set_clkdiv(struct davinci_mcasp *mcasp, int div_id, |
544 | int div, bool explicit) | 544 | int div, bool explicit) |
545 | { | 545 | { |
546 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | ||
547 | |||
548 | pm_runtime_get_sync(mcasp->dev); | 546 | pm_runtime_get_sync(mcasp->dev); |
549 | switch (div_id) { | 547 | switch (div_id) { |
550 | case 0: /* MCLK divider */ | 548 | case MCASP_CLKDIV_AUXCLK: /* MCLK divider */ |
551 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, | 549 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, |
552 | AHCLKXDIV(div - 1), AHCLKXDIV_MASK); | 550 | AHCLKXDIV(div - 1), AHCLKXDIV_MASK); |
553 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, | 551 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_AHCLKRCTL_REG, |
554 | AHCLKRDIV(div - 1), AHCLKRDIV_MASK); | 552 | AHCLKRDIV(div - 1), AHCLKRDIV_MASK); |
555 | break; | 553 | break; |
556 | 554 | ||
557 | case 1: /* BCLK divider */ | 555 | case MCASP_CLKDIV_BCLK: /* BCLK divider */ |
558 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, | 556 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, |
559 | ACLKXDIV(div - 1), ACLKXDIV_MASK); | 557 | ACLKXDIV(div - 1), ACLKXDIV_MASK); |
560 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, | 558 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, |
@@ -563,7 +561,8 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, | |||
563 | mcasp->bclk_div = div; | 561 | mcasp->bclk_div = div; |
564 | break; | 562 | break; |
565 | 563 | ||
566 | case 2: /* | 564 | case MCASP_CLKDIV_BCLK_FS_RATIO: |
565 | /* | ||
567 | * BCLK/LRCLK ratio descries how many bit-clock cycles | 566 | * BCLK/LRCLK ratio descries how many bit-clock cycles |
568 | * fit into one frame. The clock ratio is given for a | 567 | * fit into one frame. The clock ratio is given for a |
569 | * full period of data (for I2S format both left and | 568 | * full period of data (for I2S format both left and |
@@ -591,7 +590,9 @@ static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, | |||
591 | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, | 590 | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, |
592 | int div) | 591 | int div) |
593 | { | 592 | { |
594 | return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1); | 593 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); |
594 | |||
595 | return __davinci_mcasp_set_clkdiv(mcasp, div_id, div, 1); | ||
595 | } | 596 | } |
596 | 597 | ||
597 | static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 598 | static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
@@ -999,27 +1000,53 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp, | |||
999 | } | 1000 | } |
1000 | 1001 | ||
1001 | static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp, | 1002 | static int davinci_mcasp_calc_clk_div(struct davinci_mcasp *mcasp, |
1002 | unsigned int bclk_freq, | 1003 | unsigned int bclk_freq, bool set) |
1003 | int *error_ppm) | ||
1004 | { | 1004 | { |
1005 | int div = mcasp->sysclk_freq / bclk_freq; | 1005 | int error_ppm; |
1006 | int rem = mcasp->sysclk_freq % bclk_freq; | 1006 | unsigned int sysclk_freq = mcasp->sysclk_freq; |
1007 | u32 reg = mcasp_get_reg(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG); | ||
1008 | int div = sysclk_freq / bclk_freq; | ||
1009 | int rem = sysclk_freq % bclk_freq; | ||
1010 | int aux_div = 1; | ||
1011 | |||
1012 | if (div > (ACLKXDIV_MASK + 1)) { | ||
1013 | if (reg & AHCLKXE) { | ||
1014 | aux_div = div / (ACLKXDIV_MASK + 1); | ||
1015 | if (div % (ACLKXDIV_MASK + 1)) | ||
1016 | aux_div++; | ||
1017 | |||
1018 | sysclk_freq /= aux_div; | ||
1019 | div = sysclk_freq / bclk_freq; | ||
1020 | rem = sysclk_freq % bclk_freq; | ||
1021 | } else if (set) { | ||
1022 | dev_warn(mcasp->dev, "Too fast reference clock (%u)\n", | ||
1023 | sysclk_freq); | ||
1024 | } | ||
1025 | } | ||
1007 | 1026 | ||
1008 | if (rem != 0) { | 1027 | if (rem != 0) { |
1009 | if (div == 0 || | 1028 | if (div == 0 || |
1010 | ((mcasp->sysclk_freq / div) - bclk_freq) > | 1029 | ((sysclk_freq / div) - bclk_freq) > |
1011 | (bclk_freq - (mcasp->sysclk_freq / (div+1)))) { | 1030 | (bclk_freq - (sysclk_freq / (div+1)))) { |
1012 | div++; | 1031 | div++; |
1013 | rem = rem - bclk_freq; | 1032 | rem = rem - bclk_freq; |
1014 | } | 1033 | } |
1015 | } | 1034 | } |
1016 | if (error_ppm) | 1035 | error_ppm = (div*1000000 + (int)div64_long(1000000LL*rem, |
1017 | *error_ppm = | 1036 | (int)bclk_freq)) / div - 1000000; |
1018 | (div*1000000 + (int)div64_long(1000000LL*rem, | 1037 | |
1019 | (int)bclk_freq)) | 1038 | if (set) { |
1020 | /div - 1000000; | 1039 | if (error_ppm) |
1040 | dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n", | ||
1041 | error_ppm); | ||
1042 | |||
1043 | __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_BCLK, div, 0); | ||
1044 | if (reg & AHCLKXE) | ||
1045 | __davinci_mcasp_set_clkdiv(mcasp, MCASP_CLKDIV_AUXCLK, | ||
1046 | aux_div, 0); | ||
1047 | } | ||
1021 | 1048 | ||
1022 | return div; | 1049 | return error_ppm; |
1023 | } | 1050 | } |
1024 | 1051 | ||
1025 | static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | 1052 | static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, |
@@ -1044,18 +1071,11 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
1044 | int slots = mcasp->tdm_slots; | 1071 | int slots = mcasp->tdm_slots; |
1045 | int rate = params_rate(params); | 1072 | int rate = params_rate(params); |
1046 | int sbits = params_width(params); | 1073 | int sbits = params_width(params); |
1047 | int ppm, div; | ||
1048 | 1074 | ||
1049 | if (mcasp->slot_width) | 1075 | if (mcasp->slot_width) |
1050 | sbits = mcasp->slot_width; | 1076 | sbits = mcasp->slot_width; |
1051 | 1077 | ||
1052 | div = davinci_mcasp_calc_clk_div(mcasp, rate*sbits*slots, | 1078 | davinci_mcasp_calc_clk_div(mcasp, rate * sbits * slots, true); |
1053 | &ppm); | ||
1054 | if (ppm) | ||
1055 | dev_info(mcasp->dev, "Sample-rate is off by %d PPM\n", | ||
1056 | ppm); | ||
1057 | |||
1058 | __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0); | ||
1059 | } | 1079 | } |
1060 | 1080 | ||
1061 | ret = mcasp_common_hw_param(mcasp, substream->stream, | 1081 | ret = mcasp_common_hw_param(mcasp, substream->stream, |
@@ -1166,7 +1186,8 @@ static int davinci_mcasp_hw_rule_rate(struct snd_pcm_hw_params *params, | |||
1166 | davinci_mcasp_dai_rates[i]; | 1186 | davinci_mcasp_dai_rates[i]; |
1167 | int ppm; | 1187 | int ppm; |
1168 | 1188 | ||
1169 | davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, &ppm); | 1189 | ppm = davinci_mcasp_calc_clk_div(rd->mcasp, bclk_freq, |
1190 | false); | ||
1170 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { | 1191 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { |
1171 | if (range.empty) { | 1192 | if (range.empty) { |
1172 | range.min = davinci_mcasp_dai_rates[i]; | 1193 | range.min = davinci_mcasp_dai_rates[i]; |
@@ -1205,8 +1226,9 @@ static int davinci_mcasp_hw_rule_format(struct snd_pcm_hw_params *params, | |||
1205 | if (rd->mcasp->slot_width) | 1226 | if (rd->mcasp->slot_width) |
1206 | sbits = rd->mcasp->slot_width; | 1227 | sbits = rd->mcasp->slot_width; |
1207 | 1228 | ||
1208 | davinci_mcasp_calc_clk_div(rd->mcasp, sbits*slots*rate, | 1229 | ppm = davinci_mcasp_calc_clk_div(rd->mcasp, |
1209 | &ppm); | 1230 | sbits * slots * rate, |
1231 | false); | ||
1210 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { | 1232 | if (abs(ppm) < DAVINCI_MAX_RATE_ERROR_PPM) { |
1211 | snd_mask_set(&nfmt, i); | 1233 | snd_mask_set(&nfmt, i); |
1212 | count++; | 1234 | count++; |
@@ -1230,11 +1252,15 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
1230 | int i, dir; | 1252 | int i, dir; |
1231 | int tdm_slots = mcasp->tdm_slots; | 1253 | int tdm_slots = mcasp->tdm_slots; |
1232 | 1254 | ||
1233 | if (mcasp->tdm_mask[substream->stream]) | 1255 | /* Do not allow more then one stream per direction */ |
1234 | tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]); | 1256 | if (mcasp->substreams[substream->stream]) |
1257 | return -EBUSY; | ||
1235 | 1258 | ||
1236 | mcasp->substreams[substream->stream] = substream; | 1259 | mcasp->substreams[substream->stream] = substream; |
1237 | 1260 | ||
1261 | if (mcasp->tdm_mask[substream->stream]) | ||
1262 | tdm_slots = hweight32(mcasp->tdm_mask[substream->stream]); | ||
1263 | |||
1238 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 1264 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
1239 | return 0; | 1265 | return 0; |
1240 | 1266 | ||
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index a3be108a8c17..1e8787fb3fb7 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -306,4 +306,9 @@ | |||
306 | #define NUMEVT(x) (((x) & 0xFF) << 8) | 306 | #define NUMEVT(x) (((x) & 0xFF) << 8) |
307 | #define NUMDMA_MASK (0xFF) | 307 | #define NUMDMA_MASK (0xFF) |
308 | 308 | ||
309 | /* clock divider IDs */ | ||
310 | #define MCASP_CLKDIV_AUXCLK 0 /* HCLK divider from AUXCLK */ | ||
311 | #define MCASP_CLKDIV_BCLK 1 /* BCLK divider from HCLK */ | ||
312 | #define MCASP_CLKDIV_BCLK_FS_RATIO 2 /* to set BCLK FS ration */ | ||
313 | |||
309 | #endif /* DAVINCI_MCASP_H */ | 314 | #endif /* DAVINCI_MCASP_H */ |
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index bff258d7bcea..0db69b7e9617 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -100,6 +100,7 @@ struct dw_i2s_dev { | |||
100 | struct device *dev; | 100 | struct device *dev; |
101 | u32 ccr; | 101 | u32 ccr; |
102 | u32 xfer_resolution; | 102 | u32 xfer_resolution; |
103 | u32 fifo_th; | ||
103 | 104 | ||
104 | /* data related to DMA transfers b/w i2s and DMAC */ | 105 | /* data related to DMA transfers b/w i2s and DMAC */ |
105 | union dw_i2s_snd_dma_data play_dma_data; | 106 | union dw_i2s_snd_dma_data play_dma_data; |
@@ -147,17 +148,18 @@ static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream) | |||
147 | static void i2s_start(struct dw_i2s_dev *dev, | 148 | static void i2s_start(struct dw_i2s_dev *dev, |
148 | struct snd_pcm_substream *substream) | 149 | struct snd_pcm_substream *substream) |
149 | { | 150 | { |
151 | struct i2s_clk_config_data *config = &dev->config; | ||
150 | u32 i, irq; | 152 | u32 i, irq; |
151 | i2s_write_reg(dev->i2s_base, IER, 1); | 153 | i2s_write_reg(dev->i2s_base, IER, 1); |
152 | 154 | ||
153 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 155 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
154 | for (i = 0; i < 4; i++) { | 156 | for (i = 0; i < (config->chan_nr / 2); i++) { |
155 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | 157 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); |
156 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x30); | 158 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x30); |
157 | } | 159 | } |
158 | i2s_write_reg(dev->i2s_base, ITER, 1); | 160 | i2s_write_reg(dev->i2s_base, ITER, 1); |
159 | } else { | 161 | } else { |
160 | for (i = 0; i < 4; i++) { | 162 | for (i = 0; i < (config->chan_nr / 2); i++) { |
161 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | 163 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); |
162 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x03); | 164 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x03); |
163 | } | 165 | } |
@@ -231,14 +233,16 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) | |||
231 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 233 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
232 | i2s_write_reg(dev->i2s_base, TCR(ch_reg), | 234 | i2s_write_reg(dev->i2s_base, TCR(ch_reg), |
233 | dev->xfer_resolution); | 235 | dev->xfer_resolution); |
234 | i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); | 236 | i2s_write_reg(dev->i2s_base, TFCR(ch_reg), |
237 | dev->fifo_th - 1); | ||
235 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); | 238 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); |
236 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); | 239 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); |
237 | i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); | 240 | i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); |
238 | } else { | 241 | } else { |
239 | i2s_write_reg(dev->i2s_base, RCR(ch_reg), | 242 | i2s_write_reg(dev->i2s_base, RCR(ch_reg), |
240 | dev->xfer_resolution); | 243 | dev->xfer_resolution); |
241 | i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); | 244 | i2s_write_reg(dev->i2s_base, RFCR(ch_reg), |
245 | dev->fifo_th - 1); | ||
242 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); | 246 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); |
243 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); | 247 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); |
244 | i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); | 248 | i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); |
@@ -498,6 +502,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, | |||
498 | */ | 502 | */ |
499 | u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); | 503 | u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); |
500 | u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2); | 504 | u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2); |
505 | u32 fifo_depth = 1 << (1 + COMP1_FIFO_DEPTH_GLOBAL(comp1)); | ||
501 | u32 idx; | 506 | u32 idx; |
502 | 507 | ||
503 | if (dev->capability & DWC_I2S_RECORD && | 508 | if (dev->capability & DWC_I2S_RECORD && |
@@ -536,6 +541,7 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, | |||
536 | dev->capability |= DW_I2S_SLAVE; | 541 | dev->capability |= DW_I2S_SLAVE; |
537 | } | 542 | } |
538 | 543 | ||
544 | dev->fifo_th = fifo_depth / 2; | ||
539 | return 0; | 545 | return 0; |
540 | } | 546 | } |
541 | 547 | ||
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 0754df771e3b..2147994ab46f 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #include <sound/core.h> | 21 | #include <sound/core.h> |
22 | #include <sound/dmaengine_pcm.h> | 22 | #include <sound/dmaengine_pcm.h> |
23 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
24 | #include <linux/mfd/syscon.h> | ||
25 | #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> | ||
24 | 26 | ||
25 | #include "fsl_sai.h" | 27 | #include "fsl_sai.h" |
26 | #include "imx-pcm.h" | 28 | #include "imx-pcm.h" |
@@ -786,10 +788,12 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
786 | { | 788 | { |
787 | struct device_node *np = pdev->dev.of_node; | 789 | struct device_node *np = pdev->dev.of_node; |
788 | struct fsl_sai *sai; | 790 | struct fsl_sai *sai; |
791 | struct regmap *gpr; | ||
789 | struct resource *res; | 792 | struct resource *res; |
790 | void __iomem *base; | 793 | void __iomem *base; |
791 | char tmp[8]; | 794 | char tmp[8]; |
792 | int irq, ret, i; | 795 | int irq, ret, i; |
796 | int index; | ||
793 | 797 | ||
794 | sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); | 798 | sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); |
795 | if (!sai) | 799 | if (!sai) |
@@ -797,7 +801,8 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
797 | 801 | ||
798 | sai->pdev = pdev; | 802 | sai->pdev = pdev; |
799 | 803 | ||
800 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) | 804 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai") || |
805 | of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai")) | ||
801 | sai->sai_on_imx = true; | 806 | sai->sai_on_imx = true; |
802 | 807 | ||
803 | sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); | 808 | sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); |
@@ -877,6 +882,22 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
877 | fsl_sai_dai.symmetric_samplebits = 0; | 882 | fsl_sai_dai.symmetric_samplebits = 0; |
878 | } | 883 | } |
879 | 884 | ||
885 | if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && | ||
886 | of_device_is_compatible(pdev->dev.of_node, "fsl,imx6ul-sai")) { | ||
887 | gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); | ||
888 | if (IS_ERR(gpr)) { | ||
889 | dev_err(&pdev->dev, "cannot find iomuxc registers\n"); | ||
890 | return PTR_ERR(gpr); | ||
891 | } | ||
892 | |||
893 | index = of_alias_get_id(np, "sai"); | ||
894 | if (index < 0) | ||
895 | return index; | ||
896 | |||
897 | regmap_update_bits(gpr, IOMUXC_GPR1, MCLK_DIR(index), | ||
898 | MCLK_DIR(index)); | ||
899 | } | ||
900 | |||
880 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; | 901 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; |
881 | sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; | 902 | sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; |
882 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; | 903 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; |
@@ -898,6 +919,7 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
898 | static const struct of_device_id fsl_sai_ids[] = { | 919 | static const struct of_device_id fsl_sai_ids[] = { |
899 | { .compatible = "fsl,vf610-sai", }, | 920 | { .compatible = "fsl,vf610-sai", }, |
900 | { .compatible = "fsl,imx6sx-sai", }, | 921 | { .compatible = "fsl,imx6sx-sai", }, |
922 | { .compatible = "fsl,imx6ul-sai", }, | ||
901 | { /* sentinel */ } | 923 | { /* sentinel */ } |
902 | }; | 924 | }; |
903 | MODULE_DEVICE_TABLE(of, fsl_sai_ids); | 925 | MODULE_DEVICE_TABLE(of, fsl_sai_ids); |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index ed8de1035cda..632ecc0e3956 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -137,6 +137,7 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) | |||
137 | case CCSR_SSI_SACDAT: | 137 | case CCSR_SSI_SACDAT: |
138 | case CCSR_SSI_SATAG: | 138 | case CCSR_SSI_SATAG: |
139 | case CCSR_SSI_SACCST: | 139 | case CCSR_SSI_SACCST: |
140 | case CCSR_SSI_SOR: | ||
140 | return true; | 141 | return true; |
141 | default: | 142 | default: |
142 | return false; | 143 | return false; |
@@ -261,6 +262,7 @@ struct fsl_ssi_private { | |||
261 | struct fsl_ssi_dbg dbg_stats; | 262 | struct fsl_ssi_dbg dbg_stats; |
262 | 263 | ||
263 | const struct fsl_ssi_soc_data *soc; | 264 | const struct fsl_ssi_soc_data *soc; |
265 | struct device *dev; | ||
264 | }; | 266 | }; |
265 | 267 | ||
266 | /* | 268 | /* |
@@ -400,6 +402,26 @@ static void fsl_ssi_rxtx_config(struct fsl_ssi_private *ssi_private, | |||
400 | } | 402 | } |
401 | 403 | ||
402 | /* | 404 | /* |
405 | * Clear RX or TX FIFO to remove samples from the previous | ||
406 | * stream session which may be still present in the FIFO and | ||
407 | * may introduce bad samples and/or channel slipping. | ||
408 | * | ||
409 | * Note: The SOR is not documented in recent IMX datasheet, but | ||
410 | * is described in IMX51 reference manual at section 56.3.3.15. | ||
411 | */ | ||
412 | static void fsl_ssi_fifo_clear(struct fsl_ssi_private *ssi_private, | ||
413 | bool is_rx) | ||
414 | { | ||
415 | if (is_rx) { | ||
416 | regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, | ||
417 | CCSR_SSI_SOR_RX_CLR, CCSR_SSI_SOR_RX_CLR); | ||
418 | } else { | ||
419 | regmap_update_bits(ssi_private->regs, CCSR_SSI_SOR, | ||
420 | CCSR_SSI_SOR_TX_CLR, CCSR_SSI_SOR_TX_CLR); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | /* | ||
403 | * Calculate the bits that have to be disabled for the current stream that is | 425 | * Calculate the bits that have to be disabled for the current stream that is |
404 | * getting disabled. This keeps the bits enabled that are necessary for the | 426 | * getting disabled. This keeps the bits enabled that are necessary for the |
405 | * second stream to work if 'stream_active' is true. | 427 | * second stream to work if 'stream_active' is true. |
@@ -474,9 +496,11 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, | |||
474 | * (online configuration) | 496 | * (online configuration) |
475 | */ | 497 | */ |
476 | if (enable) { | 498 | if (enable) { |
477 | regmap_update_bits(regs, CCSR_SSI_SIER, vals->sier, vals->sier); | 499 | fsl_ssi_fifo_clear(ssi_private, vals->scr & CCSR_SSI_SCR_RE); |
500 | |||
478 | regmap_update_bits(regs, CCSR_SSI_SRCR, vals->srcr, vals->srcr); | 501 | regmap_update_bits(regs, CCSR_SSI_SRCR, vals->srcr, vals->srcr); |
479 | regmap_update_bits(regs, CCSR_SSI_STCR, vals->stcr, vals->stcr); | 502 | regmap_update_bits(regs, CCSR_SSI_STCR, vals->stcr, vals->stcr); |
503 | regmap_update_bits(regs, CCSR_SSI_SIER, vals->sier, vals->sier); | ||
480 | } else { | 504 | } else { |
481 | u32 sier; | 505 | u32 sier; |
482 | u32 srcr; | 506 | u32 srcr; |
@@ -506,8 +530,40 @@ static void fsl_ssi_config(struct fsl_ssi_private *ssi_private, bool enable, | |||
506 | 530 | ||
507 | config_done: | 531 | config_done: |
508 | /* Enabling of subunits is done after configuration */ | 532 | /* Enabling of subunits is done after configuration */ |
509 | if (enable) | 533 | if (enable) { |
534 | if (ssi_private->use_dma && (vals->scr & CCSR_SSI_SCR_TE)) { | ||
535 | /* | ||
536 | * Be sure the Tx FIFO is filled when TE is set. | ||
537 | * Otherwise, there are some chances to start the | ||
538 | * playback with some void samples inserted first, | ||
539 | * generating a channel slip. | ||
540 | * | ||
541 | * First, SSIEN must be set, to let the FIFO be filled. | ||
542 | * | ||
543 | * Notes: | ||
544 | * - Limit this fix to the DMA case until FIQ cases can | ||
545 | * be tested. | ||
546 | * - Limit the length of the busy loop to not lock the | ||
547 | * system too long, even if 1-2 loops are sufficient | ||
548 | * in general. | ||
549 | */ | ||
550 | int i; | ||
551 | int max_loop = 100; | ||
552 | regmap_update_bits(regs, CCSR_SSI_SCR, | ||
553 | CCSR_SSI_SCR_SSIEN, CCSR_SSI_SCR_SSIEN); | ||
554 | for (i = 0; i < max_loop; i++) { | ||
555 | u32 sfcsr; | ||
556 | regmap_read(regs, CCSR_SSI_SFCSR, &sfcsr); | ||
557 | if (CCSR_SSI_SFCSR_TFCNT0(sfcsr)) | ||
558 | break; | ||
559 | } | ||
560 | if (i == max_loop) { | ||
561 | dev_err(ssi_private->dev, | ||
562 | "Timeout waiting TX FIFO filling\n"); | ||
563 | } | ||
564 | } | ||
510 | regmap_update_bits(regs, CCSR_SSI_SCR, vals->scr, vals->scr); | 565 | regmap_update_bits(regs, CCSR_SSI_SCR, vals->scr, vals->scr); |
566 | } | ||
511 | } | 567 | } |
512 | 568 | ||
513 | 569 | ||
@@ -670,6 +726,15 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, | |||
670 | if (IS_ERR(ssi_private->baudclk)) | 726 | if (IS_ERR(ssi_private->baudclk)) |
671 | return -EINVAL; | 727 | return -EINVAL; |
672 | 728 | ||
729 | /* | ||
730 | * Hardware limitation: The bclk rate must be | ||
731 | * never greater than 1/5 IPG clock rate | ||
732 | */ | ||
733 | if (freq * 5 > clk_get_rate(ssi_private->clk)) { | ||
734 | dev_err(cpu_dai->dev, "bitclk > ipgclk/5\n"); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
673 | baudclk_is_used = ssi_private->baudclk_streams & ~(BIT(substream->stream)); | 738 | baudclk_is_used = ssi_private->baudclk_streams & ~(BIT(substream->stream)); |
674 | 739 | ||
675 | /* It should be already enough to divide clock by setting pm alone */ | 740 | /* It should be already enough to divide clock by setting pm alone */ |
@@ -686,13 +751,6 @@ static int fsl_ssi_set_bclk(struct snd_pcm_substream *substream, | |||
686 | else | 751 | else |
687 | clkrate = clk_round_rate(ssi_private->baudclk, tmprate); | 752 | clkrate = clk_round_rate(ssi_private->baudclk, tmprate); |
688 | 753 | ||
689 | /* | ||
690 | * Hardware limitation: The bclk rate must be | ||
691 | * never greater than 1/5 IPG clock rate | ||
692 | */ | ||
693 | if (clkrate * 5 > clk_get_rate(ssi_private->clk)) | ||
694 | continue; | ||
695 | |||
696 | clkrate /= factor; | 754 | clkrate /= factor; |
697 | afreq = clkrate / (i + 1); | 755 | afreq = clkrate / (i + 1); |
698 | 756 | ||
@@ -1158,14 +1216,14 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = { | |||
1158 | .playback = { | 1216 | .playback = { |
1159 | .stream_name = "CPU-Playback", | 1217 | .stream_name = "CPU-Playback", |
1160 | .channels_min = 1, | 1218 | .channels_min = 1, |
1161 | .channels_max = 2, | 1219 | .channels_max = 32, |
1162 | .rates = FSLSSI_I2S_RATES, | 1220 | .rates = FSLSSI_I2S_RATES, |
1163 | .formats = FSLSSI_I2S_FORMATS, | 1221 | .formats = FSLSSI_I2S_FORMATS, |
1164 | }, | 1222 | }, |
1165 | .capture = { | 1223 | .capture = { |
1166 | .stream_name = "CPU-Capture", | 1224 | .stream_name = "CPU-Capture", |
1167 | .channels_min = 1, | 1225 | .channels_min = 1, |
1168 | .channels_max = 2, | 1226 | .channels_max = 32, |
1169 | .rates = FSLSSI_I2S_RATES, | 1227 | .rates = FSLSSI_I2S_RATES, |
1170 | .formats = FSLSSI_I2S_FORMATS, | 1228 | .formats = FSLSSI_I2S_FORMATS, |
1171 | }, | 1229 | }, |
@@ -1402,6 +1460,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1402 | } | 1460 | } |
1403 | 1461 | ||
1404 | ssi_private->soc = of_id->data; | 1462 | ssi_private->soc = of_id->data; |
1463 | ssi_private->dev = &pdev->dev; | ||
1405 | 1464 | ||
1406 | sprop = of_get_property(np, "fsl,mode", NULL); | 1465 | sprop = of_get_property(np, "fsl,mode", NULL); |
1407 | if (sprop) { | 1466 | if (sprop) { |
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index e63cd5ecfd8f..dac6688540dc 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c | |||
@@ -220,7 +220,7 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, | |||
220 | ret = dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area, | 220 | ret = dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area, |
221 | runtime->dma_addr, runtime->dma_bytes); | 221 | runtime->dma_addr, runtime->dma_bytes); |
222 | 222 | ||
223 | pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret, | 223 | pr_debug("%s: ret: %d %p %pad 0x%08zx\n", __func__, ret, |
224 | runtime->dma_area, | 224 | runtime->dma_area, |
225 | &runtime->dma_addr, | 225 | &runtime->dma_addr, |
226 | runtime->dma_bytes); | 226 | runtime->dma_bytes); |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2389ab47e25f..466492b7d4f5 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -643,6 +643,7 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match); | |||
643 | static struct platform_driver asoc_simple_card = { | 643 | static struct platform_driver asoc_simple_card = { |
644 | .driver = { | 644 | .driver = { |
645 | .name = "asoc-simple-card", | 645 | .name = "asoc-simple-card", |
646 | .pm = &snd_soc_pm_ops, | ||
646 | .of_match_table = asoc_simple_of_match, | 647 | .of_match_table = asoc_simple_of_match, |
647 | }, | 648 | }, |
648 | .probe = asoc_simple_card_probe, | 649 | .probe = asoc_simple_card_probe, |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index b3e6c2300457..91c15abb625e 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -58,6 +58,21 @@ config SND_SOC_INTEL_HASWELL_MACH | |||
58 | Say Y if you have such a device | 58 | Say Y if you have such a device |
59 | If unsure select "N". | 59 | If unsure select "N". |
60 | 60 | ||
61 | config SND_SOC_INTEL_BXT_RT298_MACH | ||
62 | tristate "ASoC Audio driver for Broxton with RT298 I2S mode" | ||
63 | depends on X86 && ACPI && I2C | ||
64 | select SND_SOC_INTEL_SST | ||
65 | select SND_SOC_INTEL_SKYLAKE | ||
66 | select SND_SOC_RT298 | ||
67 | select SND_SOC_DMIC | ||
68 | select SND_SOC_HDAC_HDMI | ||
69 | select SND_HDA_DSP_LOADER | ||
70 | help | ||
71 | This adds support for ASoC machine driver for Broxton platforms | ||
72 | with RT286 I2S audio codec. | ||
73 | Say Y if you have such a device | ||
74 | If unsure select "N". | ||
75 | |||
61 | config SND_SOC_INTEL_BYT_RT5640_MACH | 76 | config SND_SOC_INTEL_BYT_RT5640_MACH |
62 | tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" | 77 | tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" |
63 | depends on X86_INTEL_LPSS && I2C | 78 | depends on X86_INTEL_LPSS && I2C |
@@ -162,8 +177,8 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH | |||
162 | config SND_SOC_INTEL_SKYLAKE | 177 | config SND_SOC_INTEL_SKYLAKE |
163 | tristate | 178 | tristate |
164 | select SND_HDA_EXT_CORE | 179 | select SND_HDA_EXT_CORE |
180 | select SND_HDA_DSP_LOADER | ||
165 | select SND_SOC_TOPOLOGY | 181 | select SND_SOC_TOPOLOGY |
166 | select SND_HDA_I915 | ||
167 | select SND_SOC_INTEL_SST | 182 | select SND_SOC_INTEL_SST |
168 | 183 | ||
169 | config SND_SOC_INTEL_SKL_RT286_MACH | 184 | config SND_SOC_INTEL_SKL_RT286_MACH |
diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index b97e6adcf1b2..98720a93de8a 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c | |||
@@ -195,7 +195,7 @@ static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol | |||
195 | 195 | ||
196 | if (e->w && e->w->power) | 196 | if (e->w && e->w->power) |
197 | ret = sst_send_slot_map(drv); | 197 | ret = sst_send_slot_map(drv); |
198 | else | 198 | else if (!e->w) |
199 | dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n", | 199 | dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n", |
200 | kcontrol->id.name); | 200 | kcontrol->id.name); |
201 | return ret; | 201 | return ret; |
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 3310c0f9c356..a8506774f510 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile | |||
@@ -2,6 +2,7 @@ snd-soc-sst-haswell-objs := haswell.o | |||
2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
4 | snd-soc-sst-broadwell-objs := broadwell.o | 4 | snd-soc-sst-broadwell-objs := broadwell.o |
5 | snd-soc-sst-bxt-rt298-objs := bxt_rt298.o | ||
5 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o | 6 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o |
6 | snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o | 7 | snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o |
7 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | 8 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o |
@@ -14,6 +15,7 @@ snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o | |||
14 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 15 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
15 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 16 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
16 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | 17 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o |
18 | obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o | ||
17 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | 19 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o |
18 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o | 20 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o |
19 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o | 21 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o |
diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 3f8a1e10bed0..7486a0022fde 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c | |||
@@ -201,7 +201,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
201 | { | 201 | { |
202 | /* SSP0 - Codec */ | 202 | /* SSP0 - Codec */ |
203 | .name = "Codec", | 203 | .name = "Codec", |
204 | .be_id = 0, | 204 | .id = 0, |
205 | .cpu_dai_name = "snd-soc-dummy-dai", | 205 | .cpu_dai_name = "snd-soc-dummy-dai", |
206 | .platform_name = "snd-soc-dummy", | 206 | .platform_name = "snd-soc-dummy", |
207 | .no_pcm = 1, | 207 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c new file mode 100644 index 000000000000..f4787515c0ed --- /dev/null +++ b/sound/soc/intel/boards/bxt_rt298.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * Intel Broxton-P I2S Machine Driver | ||
3 | * | ||
4 | * Copyright (C) 2014-2016, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Modified from: | ||
7 | * Intel Skylake I2S Machine driver | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/jack.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include "../../codecs/hdac_hdmi.h" | ||
27 | #include "../../codecs/rt298.h" | ||
28 | |||
29 | static struct snd_soc_jack broxton_headset; | ||
30 | /* Headset jack detection DAPM pins */ | ||
31 | |||
32 | enum { | ||
33 | BXT_DPCM_AUDIO_PB = 0, | ||
34 | BXT_DPCM_AUDIO_CP, | ||
35 | BXT_DPCM_AUDIO_REF_CP, | ||
36 | BXT_DPCM_AUDIO_HDMI1_PB, | ||
37 | BXT_DPCM_AUDIO_HDMI2_PB, | ||
38 | BXT_DPCM_AUDIO_HDMI3_PB, | ||
39 | }; | ||
40 | |||
41 | static struct snd_soc_jack_pin broxton_headset_pins[] = { | ||
42 | { | ||
43 | .pin = "Mic Jack", | ||
44 | .mask = SND_JACK_MICROPHONE, | ||
45 | }, | ||
46 | { | ||
47 | .pin = "Headphone Jack", | ||
48 | .mask = SND_JACK_HEADPHONE, | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | static const struct snd_kcontrol_new broxton_controls[] = { | ||
53 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
54 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
55 | SOC_DAPM_PIN_SWITCH("Mic Jack"), | ||
56 | }; | ||
57 | |||
58 | static const struct snd_soc_dapm_widget broxton_widgets[] = { | ||
59 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
60 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
61 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
62 | SND_SOC_DAPM_MIC("DMIC2", NULL), | ||
63 | SND_SOC_DAPM_MIC("SoC DMIC", NULL), | ||
64 | SND_SOC_DAPM_SPK("HDMI1", NULL), | ||
65 | SND_SOC_DAPM_SPK("HDMI2", NULL), | ||
66 | SND_SOC_DAPM_SPK("HDMI3", NULL), | ||
67 | }; | ||
68 | |||
69 | static const struct snd_soc_dapm_route broxton_rt298_map[] = { | ||
70 | /* speaker */ | ||
71 | {"Speaker", NULL, "SPOR"}, | ||
72 | {"Speaker", NULL, "SPOL"}, | ||
73 | |||
74 | /* HP jack connectors - unknown if we have jack detect */ | ||
75 | {"Headphone Jack", NULL, "HPO Pin"}, | ||
76 | |||
77 | /* other jacks */ | ||
78 | {"MIC1", NULL, "Mic Jack"}, | ||
79 | |||
80 | /* digital mics */ | ||
81 | {"DMIC1 Pin", NULL, "DMIC2"}, | ||
82 | {"DMic", NULL, "SoC DMIC"}, | ||
83 | |||
84 | {"HDMI1", NULL, "hif5 Output"}, | ||
85 | {"HDMI2", NULL, "hif6 Output"}, | ||
86 | {"HDMI3", NULL, "hif7 Output"}, | ||
87 | |||
88 | /* CODEC BE connections */ | ||
89 | { "AIF1 Playback", NULL, "ssp5 Tx"}, | ||
90 | { "ssp5 Tx", NULL, "codec0_out"}, | ||
91 | |||
92 | { "codec0_in", NULL, "ssp5 Rx" }, | ||
93 | { "ssp5 Rx", NULL, "AIF1 Capture" }, | ||
94 | |||
95 | { "dmic01_hifi", NULL, "DMIC01 Rx" }, | ||
96 | { "DMIC01 Rx", NULL, "Capture" }, | ||
97 | |||
98 | { "hifi3", NULL, "iDisp3 Tx"}, | ||
99 | { "iDisp3 Tx", NULL, "iDisp3_out"}, | ||
100 | { "hifi2", NULL, "iDisp2 Tx"}, | ||
101 | { "iDisp2 Tx", NULL, "iDisp2_out"}, | ||
102 | { "hifi1", NULL, "iDisp1 Tx"}, | ||
103 | { "iDisp1 Tx", NULL, "iDisp1_out"}, | ||
104 | |||
105 | }; | ||
106 | |||
107 | static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) | ||
108 | { | ||
109 | struct snd_soc_codec *codec = rtd->codec; | ||
110 | int ret = 0; | ||
111 | |||
112 | ret = snd_soc_card_jack_new(rtd->card, "Headset", | ||
113 | SND_JACK_HEADSET | SND_JACK_BTN_0, | ||
114 | &broxton_headset, | ||
115 | broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins)); | ||
116 | |||
117 | if (ret) | ||
118 | return ret; | ||
119 | |||
120 | rt298_mic_detect(codec, &broxton_headset); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) | ||
125 | { | ||
126 | struct snd_soc_dai *dai = rtd->codec_dai; | ||
127 | |||
128 | return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); | ||
129 | } | ||
130 | |||
131 | static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, | ||
132 | struct snd_pcm_hw_params *params) | ||
133 | { | ||
134 | struct snd_interval *rate = hw_param_interval(params, | ||
135 | SNDRV_PCM_HW_PARAM_RATE); | ||
136 | struct snd_interval *channels = hw_param_interval(params, | ||
137 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
138 | struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
139 | |||
140 | /* The ADSP will covert the FE rate to 48k, stereo */ | ||
141 | rate->min = rate->max = 48000; | ||
142 | channels->min = channels->max = 2; | ||
143 | |||
144 | /* set SSP5 to 24 bit */ | ||
145 | snd_mask_none(fmt); | ||
146 | snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, | ||
152 | struct snd_pcm_hw_params *params) | ||
153 | { | ||
154 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
155 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
156 | int ret; | ||
157 | |||
158 | ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, | ||
159 | 19200000, SND_SOC_CLOCK_IN); | ||
160 | if (ret < 0) { | ||
161 | dev_err(rtd->dev, "can't set codec sysclk configuration\n"); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static struct snd_soc_ops broxton_rt298_ops = { | ||
169 | .hw_params = broxton_rt298_hw_params, | ||
170 | }; | ||
171 | |||
172 | /* broxton digital audio interface glue - connects codec <--> CPU */ | ||
173 | static struct snd_soc_dai_link broxton_rt298_dais[] = { | ||
174 | /* Front End DAI links */ | ||
175 | [BXT_DPCM_AUDIO_PB] | ||
176 | { | ||
177 | .name = "Bxt Audio Port", | ||
178 | .stream_name = "Audio", | ||
179 | .cpu_dai_name = "System Pin", | ||
180 | .platform_name = "0000:00:0e.0", | ||
181 | .nonatomic = 1, | ||
182 | .dynamic = 1, | ||
183 | .codec_name = "snd-soc-dummy", | ||
184 | .codec_dai_name = "snd-soc-dummy-dai", | ||
185 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
186 | .dpcm_playback = 1, | ||
187 | }, | ||
188 | [BXT_DPCM_AUDIO_CP] | ||
189 | { | ||
190 | .name = "Bxt Audio Capture Port", | ||
191 | .stream_name = "Audio Record", | ||
192 | .cpu_dai_name = "System Pin", | ||
193 | .platform_name = "0000:00:0e.0", | ||
194 | .nonatomic = 1, | ||
195 | .dynamic = 1, | ||
196 | .codec_name = "snd-soc-dummy", | ||
197 | .codec_dai_name = "snd-soc-dummy-dai", | ||
198 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
199 | .dpcm_capture = 1, | ||
200 | }, | ||
201 | [BXT_DPCM_AUDIO_REF_CP] | ||
202 | { | ||
203 | .name = "Bxt Audio Reference cap", | ||
204 | .stream_name = "refcap", | ||
205 | .cpu_dai_name = "Reference Pin", | ||
206 | .codec_name = "snd-soc-dummy", | ||
207 | .codec_dai_name = "snd-soc-dummy-dai", | ||
208 | .platform_name = "0000:00:0e.0", | ||
209 | .init = NULL, | ||
210 | .dpcm_capture = 1, | ||
211 | .nonatomic = 1, | ||
212 | .dynamic = 1, | ||
213 | }, | ||
214 | [BXT_DPCM_AUDIO_HDMI1_PB] | ||
215 | { | ||
216 | .name = "Bxt HDMI Port1", | ||
217 | .stream_name = "Hdmi1", | ||
218 | .cpu_dai_name = "HDMI1 Pin", | ||
219 | .codec_name = "snd-soc-dummy", | ||
220 | .codec_dai_name = "snd-soc-dummy-dai", | ||
221 | .platform_name = "0000:00:0e.0", | ||
222 | .dpcm_playback = 1, | ||
223 | .init = NULL, | ||
224 | .nonatomic = 1, | ||
225 | .dynamic = 1, | ||
226 | }, | ||
227 | [BXT_DPCM_AUDIO_HDMI2_PB] | ||
228 | { | ||
229 | .name = "Bxt HDMI Port2", | ||
230 | .stream_name = "Hdmi2", | ||
231 | .cpu_dai_name = "HDMI2 Pin", | ||
232 | .codec_name = "snd-soc-dummy", | ||
233 | .codec_dai_name = "snd-soc-dummy-dai", | ||
234 | .platform_name = "0000:00:0e.0", | ||
235 | .dpcm_playback = 1, | ||
236 | .init = NULL, | ||
237 | .nonatomic = 1, | ||
238 | .dynamic = 1, | ||
239 | }, | ||
240 | [BXT_DPCM_AUDIO_HDMI3_PB] | ||
241 | { | ||
242 | .name = "Bxt HDMI Port3", | ||
243 | .stream_name = "Hdmi3", | ||
244 | .cpu_dai_name = "HDMI3 Pin", | ||
245 | .codec_name = "snd-soc-dummy", | ||
246 | .codec_dai_name = "snd-soc-dummy-dai", | ||
247 | .platform_name = "0000:00:0e.0", | ||
248 | .dpcm_playback = 1, | ||
249 | .init = NULL, | ||
250 | .nonatomic = 1, | ||
251 | .dynamic = 1, | ||
252 | }, | ||
253 | /* Back End DAI links */ | ||
254 | { | ||
255 | /* SSP5 - Codec */ | ||
256 | .name = "SSP5-Codec", | ||
257 | .id = 0, | ||
258 | .cpu_dai_name = "SSP5 Pin", | ||
259 | .platform_name = "0000:00:0e.0", | ||
260 | .no_pcm = 1, | ||
261 | .codec_name = "i2c-INT343A:00", | ||
262 | .codec_dai_name = "rt298-aif1", | ||
263 | .init = broxton_rt298_codec_init, | ||
264 | .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | | ||
265 | SND_SOC_DAIFMT_CBS_CFS, | ||
266 | .ignore_pmdown_time = 1, | ||
267 | .be_hw_params_fixup = broxton_ssp5_fixup, | ||
268 | .ops = &broxton_rt298_ops, | ||
269 | .dpcm_playback = 1, | ||
270 | .dpcm_capture = 1, | ||
271 | }, | ||
272 | { | ||
273 | .name = "dmic01", | ||
274 | .id = 1, | ||
275 | .cpu_dai_name = "DMIC01 Pin", | ||
276 | .codec_name = "dmic-codec", | ||
277 | .codec_dai_name = "dmic-hifi", | ||
278 | .platform_name = "0000:00:0e.0", | ||
279 | .ignore_suspend = 1, | ||
280 | .dpcm_capture = 1, | ||
281 | .no_pcm = 1, | ||
282 | }, | ||
283 | { | ||
284 | .name = "iDisp1", | ||
285 | .id = 3, | ||
286 | .cpu_dai_name = "iDisp1 Pin", | ||
287 | .codec_name = "ehdaudio0D2", | ||
288 | .codec_dai_name = "intel-hdmi-hifi1", | ||
289 | .platform_name = "0000:00:0e.0", | ||
290 | .init = broxton_hdmi_init, | ||
291 | .dpcm_playback = 1, | ||
292 | .no_pcm = 1, | ||
293 | }, | ||
294 | { | ||
295 | .name = "iDisp2", | ||
296 | .id = 4, | ||
297 | .cpu_dai_name = "iDisp2 Pin", | ||
298 | .codec_name = "ehdaudio0D2", | ||
299 | .codec_dai_name = "intel-hdmi-hifi2", | ||
300 | .platform_name = "0000:00:0e.0", | ||
301 | .init = broxton_hdmi_init, | ||
302 | .dpcm_playback = 1, | ||
303 | .no_pcm = 1, | ||
304 | }, | ||
305 | { | ||
306 | .name = "iDisp3", | ||
307 | .id = 5, | ||
308 | .cpu_dai_name = "iDisp3 Pin", | ||
309 | .codec_name = "ehdaudio0D2", | ||
310 | .codec_dai_name = "intel-hdmi-hifi3", | ||
311 | .platform_name = "0000:00:0e.0", | ||
312 | .init = broxton_hdmi_init, | ||
313 | .dpcm_playback = 1, | ||
314 | .no_pcm = 1, | ||
315 | }, | ||
316 | }; | ||
317 | |||
318 | /* broxton audio machine driver for SPT + RT298S */ | ||
319 | static struct snd_soc_card broxton_rt298 = { | ||
320 | .name = "broxton-rt298", | ||
321 | .owner = THIS_MODULE, | ||
322 | .dai_link = broxton_rt298_dais, | ||
323 | .num_links = ARRAY_SIZE(broxton_rt298_dais), | ||
324 | .controls = broxton_controls, | ||
325 | .num_controls = ARRAY_SIZE(broxton_controls), | ||
326 | .dapm_widgets = broxton_widgets, | ||
327 | .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), | ||
328 | .dapm_routes = broxton_rt298_map, | ||
329 | .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), | ||
330 | .fully_routed = true, | ||
331 | }; | ||
332 | |||
333 | static int broxton_audio_probe(struct platform_device *pdev) | ||
334 | { | ||
335 | broxton_rt298.dev = &pdev->dev; | ||
336 | |||
337 | return devm_snd_soc_register_card(&pdev->dev, &broxton_rt298); | ||
338 | } | ||
339 | |||
340 | static struct platform_driver broxton_audio = { | ||
341 | .probe = broxton_audio_probe, | ||
342 | .driver = { | ||
343 | .name = "bxt_alc298s_i2s", | ||
344 | }, | ||
345 | }; | ||
346 | module_platform_driver(broxton_audio) | ||
347 | |||
348 | /* Module information */ | ||
349 | MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>"); | ||
350 | MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>"); | ||
351 | MODULE_DESCRIPTION("Intel SST Audio for Broxton"); | ||
352 | MODULE_LICENSE("GPL v2"); | ||
353 | MODULE_ALIAS("platform:bxt_alc298s_i2s"); | ||
diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 032a2e753f0b..88efb62439ba 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c | |||
@@ -304,7 +304,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { | |||
304 | /* back ends */ | 304 | /* back ends */ |
305 | { | 305 | { |
306 | .name = "SSP2-Codec", | 306 | .name = "SSP2-Codec", |
307 | .be_id = 1, | 307 | .id = 1, |
308 | .cpu_dai_name = "ssp2-port", | 308 | .cpu_dai_name = "ssp2-port", |
309 | .platform_name = "sst-mfld-platform", | 309 | .platform_name = "sst-mfld-platform", |
310 | .no_pcm = 1, | 310 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 1c95ccc886c4..35f591eab3c9 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c | |||
@@ -267,7 +267,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { | |||
267 | /* back ends */ | 267 | /* back ends */ |
268 | { | 268 | { |
269 | .name = "SSP2-Codec", | 269 | .name = "SSP2-Codec", |
270 | .be_id = 1, | 270 | .id = 1, |
271 | .cpu_dai_name = "ssp2-port", | 271 | .cpu_dai_name = "ssp2-port", |
272 | .platform_name = "sst-mfld-platform", | 272 | .platform_name = "sst-mfld-platform", |
273 | .no_pcm = 1, | 273 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index e609f089593a..6260df6bd49c 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c | |||
@@ -255,7 +255,7 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
255 | /* back ends */ | 255 | /* back ends */ |
256 | { | 256 | { |
257 | .name = "SSP2-Codec", | 257 | .name = "SSP2-Codec", |
258 | .be_id = 1, | 258 | .id = 1, |
259 | .cpu_dai_name = "ssp2-port", | 259 | .cpu_dai_name = "ssp2-port", |
260 | .platform_name = "sst-mfld-platform", | 260 | .platform_name = "sst-mfld-platform", |
261 | .no_pcm = 1, | 261 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 2a6f80843bc9..0618a7f1025b 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c | |||
@@ -295,7 +295,7 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
295 | /* back ends */ | 295 | /* back ends */ |
296 | { | 296 | { |
297 | .name = "SSP2-Codec", | 297 | .name = "SSP2-Codec", |
298 | .be_id = 1, | 298 | .id = 1, |
299 | .cpu_dai_name = "ssp2-port", | 299 | .cpu_dai_name = "ssp2-port", |
300 | .platform_name = "sst-mfld-platform", | 300 | .platform_name = "sst-mfld-platform", |
301 | .no_pcm = 1, | 301 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 2e5347f8f96c..df9d254baa18 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c | |||
@@ -273,7 +273,7 @@ static struct snd_soc_dai_link cht_dailink[] = { | |||
273 | { | 273 | { |
274 | /* SSP2 - Codec */ | 274 | /* SSP2 - Codec */ |
275 | .name = "SSP2-Codec", | 275 | .name = "SSP2-Codec", |
276 | .be_id = 1, | 276 | .id = 1, |
277 | .cpu_dai_name = "ssp2-port", | 277 | .cpu_dai_name = "ssp2-port", |
278 | .platform_name = "sst-mfld-platform", | 278 | .platform_name = "sst-mfld-platform", |
279 | .no_pcm = 1, | 279 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 22558572cb9c..863f1d5e2a2c 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c | |||
@@ -156,7 +156,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
156 | { | 156 | { |
157 | /* SSP0 - Codec */ | 157 | /* SSP0 - Codec */ |
158 | .name = "Codec", | 158 | .name = "Codec", |
159 | .be_id = 0, | 159 | .id = 0, |
160 | .cpu_dai_name = "snd-soc-dummy-dai", | 160 | .cpu_dai_name = "snd-soc-dummy-dai", |
161 | .platform_name = "snd-soc-dummy", | 161 | .platform_name = "snd-soc-dummy", |
162 | .no_pcm = 1, | 162 | .no_pcm = 1, |
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 72176b79a18d..d2808652b974 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c | |||
@@ -30,6 +30,16 @@ | |||
30 | static struct snd_soc_jack skylake_headset; | 30 | static struct snd_soc_jack skylake_headset; |
31 | static struct snd_soc_card skylake_audio_card; | 31 | static struct snd_soc_card skylake_audio_card; |
32 | 32 | ||
33 | struct skl_hdmi_pcm { | ||
34 | struct list_head head; | ||
35 | struct snd_soc_dai *codec_dai; | ||
36 | int device; | ||
37 | }; | ||
38 | |||
39 | struct skl_nau8825_private { | ||
40 | struct list_head hdmi_pcm_list; | ||
41 | }; | ||
42 | |||
33 | enum { | 43 | enum { |
34 | SKL_DPCM_AUDIO_PB = 0, | 44 | SKL_DPCM_AUDIO_PB = 0, |
35 | SKL_DPCM_AUDIO_CP, | 45 | SKL_DPCM_AUDIO_CP, |
@@ -192,23 +202,56 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) | |||
192 | 202 | ||
193 | static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) | 203 | static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) |
194 | { | 204 | { |
205 | struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
195 | struct snd_soc_dai *dai = rtd->codec_dai; | 206 | struct snd_soc_dai *dai = rtd->codec_dai; |
207 | struct skl_hdmi_pcm *pcm; | ||
208 | |||
209 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
210 | if (!pcm) | ||
211 | return -ENOMEM; | ||
212 | |||
213 | pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; | ||
214 | pcm->codec_dai = dai; | ||
196 | 215 | ||
197 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); | 216 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); |
217 | |||
218 | return 0; | ||
198 | } | 219 | } |
199 | 220 | ||
200 | static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) | 221 | static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) |
201 | { | 222 | { |
223 | struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
202 | struct snd_soc_dai *dai = rtd->codec_dai; | 224 | struct snd_soc_dai *dai = rtd->codec_dai; |
225 | struct skl_hdmi_pcm *pcm; | ||
226 | |||
227 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
228 | if (!pcm) | ||
229 | return -ENOMEM; | ||
230 | |||
231 | pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; | ||
232 | pcm->codec_dai = dai; | ||
203 | 233 | ||
204 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); | 234 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); |
235 | |||
236 | return 0; | ||
205 | } | 237 | } |
206 | 238 | ||
207 | static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) | 239 | static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) |
208 | { | 240 | { |
241 | struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
209 | struct snd_soc_dai *dai = rtd->codec_dai; | 242 | struct snd_soc_dai *dai = rtd->codec_dai; |
243 | struct skl_hdmi_pcm *pcm; | ||
244 | |||
245 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
246 | if (!pcm) | ||
247 | return -ENOMEM; | ||
210 | 248 | ||
211 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); | 249 | pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; |
250 | pcm->codec_dai = dai; | ||
251 | |||
252 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); | ||
253 | |||
254 | return 0; | ||
212 | } | 255 | } |
213 | 256 | ||
214 | static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) | 257 | static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) |
@@ -391,7 +434,6 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
391 | .platform_name = "0000:00:1f.3", | 434 | .platform_name = "0000:00:1f.3", |
392 | .init = NULL, | 435 | .init = NULL, |
393 | .dpcm_capture = 1, | 436 | .dpcm_capture = 1, |
394 | .ignore_suspend = 1, | ||
395 | .nonatomic = 1, | 437 | .nonatomic = 1, |
396 | .dynamic = 1, | 438 | .dynamic = 1, |
397 | .ops = &skylaye_refcap_ops, | 439 | .ops = &skylaye_refcap_ops, |
@@ -456,7 +498,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
456 | { | 498 | { |
457 | /* SSP0 - Codec */ | 499 | /* SSP0 - Codec */ |
458 | .name = "SSP0-Codec", | 500 | .name = "SSP0-Codec", |
459 | .be_id = 0, | 501 | .id = 0, |
460 | .cpu_dai_name = "SSP0 Pin", | 502 | .cpu_dai_name = "SSP0 Pin", |
461 | .platform_name = "0000:00:1f.3", | 503 | .platform_name = "0000:00:1f.3", |
462 | .no_pcm = 1, | 504 | .no_pcm = 1, |
@@ -472,7 +514,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
472 | { | 514 | { |
473 | /* SSP1 - Codec */ | 515 | /* SSP1 - Codec */ |
474 | .name = "SSP1-Codec", | 516 | .name = "SSP1-Codec", |
475 | .be_id = 1, | 517 | .id = 1, |
476 | .cpu_dai_name = "SSP1 Pin", | 518 | .cpu_dai_name = "SSP1 Pin", |
477 | .platform_name = "0000:00:1f.3", | 519 | .platform_name = "0000:00:1f.3", |
478 | .no_pcm = 1, | 520 | .no_pcm = 1, |
@@ -489,7 +531,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
489 | }, | 531 | }, |
490 | { | 532 | { |
491 | .name = "dmic01", | 533 | .name = "dmic01", |
492 | .be_id = 2, | 534 | .id = 2, |
493 | .cpu_dai_name = "DMIC01 Pin", | 535 | .cpu_dai_name = "DMIC01 Pin", |
494 | .codec_name = "dmic-codec", | 536 | .codec_name = "dmic-codec", |
495 | .codec_dai_name = "dmic-hifi", | 537 | .codec_dai_name = "dmic-hifi", |
@@ -501,7 +543,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
501 | }, | 543 | }, |
502 | { | 544 | { |
503 | .name = "iDisp1", | 545 | .name = "iDisp1", |
504 | .be_id = 3, | 546 | .id = 3, |
505 | .cpu_dai_name = "iDisp1 Pin", | 547 | .cpu_dai_name = "iDisp1 Pin", |
506 | .codec_name = "ehdaudio0D2", | 548 | .codec_name = "ehdaudio0D2", |
507 | .codec_dai_name = "intel-hdmi-hifi1", | 549 | .codec_dai_name = "intel-hdmi-hifi1", |
@@ -512,7 +554,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
512 | }, | 554 | }, |
513 | { | 555 | { |
514 | .name = "iDisp2", | 556 | .name = "iDisp2", |
515 | .be_id = 4, | 557 | .id = 4, |
516 | .cpu_dai_name = "iDisp2 Pin", | 558 | .cpu_dai_name = "iDisp2 Pin", |
517 | .codec_name = "ehdaudio0D2", | 559 | .codec_name = "ehdaudio0D2", |
518 | .codec_dai_name = "intel-hdmi-hifi2", | 560 | .codec_dai_name = "intel-hdmi-hifi2", |
@@ -523,7 +565,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
523 | }, | 565 | }, |
524 | { | 566 | { |
525 | .name = "iDisp3", | 567 | .name = "iDisp3", |
526 | .be_id = 5, | 568 | .id = 5, |
527 | .cpu_dai_name = "iDisp3 Pin", | 569 | .cpu_dai_name = "iDisp3 Pin", |
528 | .codec_name = "ehdaudio0D2", | 570 | .codec_name = "ehdaudio0D2", |
529 | .codec_dai_name = "intel-hdmi-hifi3", | 571 | .codec_dai_name = "intel-hdmi-hifi3", |
@@ -534,6 +576,21 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
534 | }, | 576 | }, |
535 | }; | 577 | }; |
536 | 578 | ||
579 | static int skylake_card_late_probe(struct snd_soc_card *card) | ||
580 | { | ||
581 | struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); | ||
582 | struct skl_hdmi_pcm *pcm; | ||
583 | int err; | ||
584 | |||
585 | list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { | ||
586 | err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); | ||
587 | if (err < 0) | ||
588 | return err; | ||
589 | } | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
537 | /* skylake audio machine driver for SPT + NAU88L25 */ | 594 | /* skylake audio machine driver for SPT + NAU88L25 */ |
538 | static struct snd_soc_card skylake_audio_card = { | 595 | static struct snd_soc_card skylake_audio_card = { |
539 | .name = "sklnau8825max", | 596 | .name = "sklnau8825max", |
@@ -547,11 +604,21 @@ static struct snd_soc_card skylake_audio_card = { | |||
547 | .dapm_routes = skylake_map, | 604 | .dapm_routes = skylake_map, |
548 | .num_dapm_routes = ARRAY_SIZE(skylake_map), | 605 | .num_dapm_routes = ARRAY_SIZE(skylake_map), |
549 | .fully_routed = true, | 606 | .fully_routed = true, |
607 | .late_probe = skylake_card_late_probe, | ||
550 | }; | 608 | }; |
551 | 609 | ||
552 | static int skylake_audio_probe(struct platform_device *pdev) | 610 | static int skylake_audio_probe(struct platform_device *pdev) |
553 | { | 611 | { |
612 | struct skl_nau8825_private *ctx; | ||
613 | |||
614 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | ||
615 | if (!ctx) | ||
616 | return -ENOMEM; | ||
617 | |||
618 | INIT_LIST_HEAD(&ctx->hdmi_pcm_list); | ||
619 | |||
554 | skylake_audio_card.dev = &pdev->dev; | 620 | skylake_audio_card.dev = &pdev->dev; |
621 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); | ||
555 | 622 | ||
556 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); | 623 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); |
557 | } | 624 | } |
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 5f1ca99ae9b0..e19aa99c4f72 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c | |||
@@ -34,6 +34,15 @@ | |||
34 | static struct snd_soc_jack skylake_headset; | 34 | static struct snd_soc_jack skylake_headset; |
35 | static struct snd_soc_card skylake_audio_card; | 35 | static struct snd_soc_card skylake_audio_card; |
36 | 36 | ||
37 | struct skl_hdmi_pcm { | ||
38 | struct list_head head; | ||
39 | struct snd_soc_dai *codec_dai; | ||
40 | int device; | ||
41 | }; | ||
42 | |||
43 | struct skl_nau88125_private { | ||
44 | struct list_head hdmi_pcm_list; | ||
45 | }; | ||
37 | enum { | 46 | enum { |
38 | SKL_DPCM_AUDIO_PB = 0, | 47 | SKL_DPCM_AUDIO_PB = 0, |
39 | SKL_DPCM_AUDIO_CP, | 48 | SKL_DPCM_AUDIO_CP, |
@@ -222,24 +231,57 @@ static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) | |||
222 | 231 | ||
223 | static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) | 232 | static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) |
224 | { | 233 | { |
234 | struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
225 | struct snd_soc_dai *dai = rtd->codec_dai; | 235 | struct snd_soc_dai *dai = rtd->codec_dai; |
236 | struct skl_hdmi_pcm *pcm; | ||
237 | |||
238 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
239 | if (!pcm) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; | ||
243 | pcm->codec_dai = dai; | ||
244 | |||
245 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); | ||
226 | 246 | ||
227 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB); | 247 | return 0; |
228 | } | 248 | } |
229 | 249 | ||
230 | static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) | 250 | static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) |
231 | { | 251 | { |
252 | struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
232 | struct snd_soc_dai *dai = rtd->codec_dai; | 253 | struct snd_soc_dai *dai = rtd->codec_dai; |
254 | struct skl_hdmi_pcm *pcm; | ||
255 | |||
256 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
257 | if (!pcm) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; | ||
261 | pcm->codec_dai = dai; | ||
233 | 262 | ||
234 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI2_PB); | 263 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); |
264 | |||
265 | return 0; | ||
235 | } | 266 | } |
236 | 267 | ||
237 | 268 | ||
238 | static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) | 269 | static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) |
239 | { | 270 | { |
271 | struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
240 | struct snd_soc_dai *dai = rtd->codec_dai; | 272 | struct snd_soc_dai *dai = rtd->codec_dai; |
273 | struct skl_hdmi_pcm *pcm; | ||
274 | |||
275 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
276 | if (!pcm) | ||
277 | return -ENOMEM; | ||
241 | 278 | ||
242 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI3_PB); | 279 | pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; |
280 | pcm->codec_dai = dai; | ||
281 | |||
282 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); | ||
283 | |||
284 | return 0; | ||
243 | } | 285 | } |
244 | 286 | ||
245 | static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) | 287 | static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) |
@@ -440,7 +482,6 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
440 | .platform_name = "0000:00:1f.3", | 482 | .platform_name = "0000:00:1f.3", |
441 | .init = NULL, | 483 | .init = NULL, |
442 | .dpcm_capture = 1, | 484 | .dpcm_capture = 1, |
443 | .ignore_suspend = 1, | ||
444 | .nonatomic = 1, | 485 | .nonatomic = 1, |
445 | .dynamic = 1, | 486 | .dynamic = 1, |
446 | .ops = &skylaye_refcap_ops, | 487 | .ops = &skylaye_refcap_ops, |
@@ -505,7 +546,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
505 | { | 546 | { |
506 | /* SSP0 - Codec */ | 547 | /* SSP0 - Codec */ |
507 | .name = "SSP0-Codec", | 548 | .name = "SSP0-Codec", |
508 | .be_id = 0, | 549 | .id = 0, |
509 | .cpu_dai_name = "SSP0 Pin", | 550 | .cpu_dai_name = "SSP0 Pin", |
510 | .platform_name = "0000:00:1f.3", | 551 | .platform_name = "0000:00:1f.3", |
511 | .no_pcm = 1, | 552 | .no_pcm = 1, |
@@ -523,7 +564,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
523 | { | 564 | { |
524 | /* SSP1 - Codec */ | 565 | /* SSP1 - Codec */ |
525 | .name = "SSP1-Codec", | 566 | .name = "SSP1-Codec", |
526 | .be_id = 1, | 567 | .id = 1, |
527 | .cpu_dai_name = "SSP1 Pin", | 568 | .cpu_dai_name = "SSP1 Pin", |
528 | .platform_name = "0000:00:1f.3", | 569 | .platform_name = "0000:00:1f.3", |
529 | .no_pcm = 1, | 570 | .no_pcm = 1, |
@@ -540,7 +581,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
540 | }, | 581 | }, |
541 | { | 582 | { |
542 | .name = "dmic01", | 583 | .name = "dmic01", |
543 | .be_id = 2, | 584 | .id = 2, |
544 | .cpu_dai_name = "DMIC01 Pin", | 585 | .cpu_dai_name = "DMIC01 Pin", |
545 | .codec_name = "dmic-codec", | 586 | .codec_name = "dmic-codec", |
546 | .codec_dai_name = "dmic-hifi", | 587 | .codec_dai_name = "dmic-hifi", |
@@ -552,7 +593,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
552 | }, | 593 | }, |
553 | { | 594 | { |
554 | .name = "iDisp1", | 595 | .name = "iDisp1", |
555 | .be_id = 3, | 596 | .id = 3, |
556 | .cpu_dai_name = "iDisp1 Pin", | 597 | .cpu_dai_name = "iDisp1 Pin", |
557 | .codec_name = "ehdaudio0D2", | 598 | .codec_name = "ehdaudio0D2", |
558 | .codec_dai_name = "intel-hdmi-hifi1", | 599 | .codec_dai_name = "intel-hdmi-hifi1", |
@@ -563,7 +604,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
563 | }, | 604 | }, |
564 | { | 605 | { |
565 | .name = "iDisp2", | 606 | .name = "iDisp2", |
566 | .be_id = 4, | 607 | .id = 4, |
567 | .cpu_dai_name = "iDisp2 Pin", | 608 | .cpu_dai_name = "iDisp2 Pin", |
568 | .codec_name = "ehdaudio0D2", | 609 | .codec_name = "ehdaudio0D2", |
569 | .codec_dai_name = "intel-hdmi-hifi2", | 610 | .codec_dai_name = "intel-hdmi-hifi2", |
@@ -574,7 +615,7 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
574 | }, | 615 | }, |
575 | { | 616 | { |
576 | .name = "iDisp3", | 617 | .name = "iDisp3", |
577 | .be_id = 5, | 618 | .id = 5, |
578 | .cpu_dai_name = "iDisp3 Pin", | 619 | .cpu_dai_name = "iDisp3 Pin", |
579 | .codec_name = "ehdaudio0D2", | 620 | .codec_name = "ehdaudio0D2", |
580 | .codec_dai_name = "intel-hdmi-hifi3", | 621 | .codec_dai_name = "intel-hdmi-hifi3", |
@@ -585,6 +626,21 @@ static struct snd_soc_dai_link skylake_dais[] = { | |||
585 | }, | 626 | }, |
586 | }; | 627 | }; |
587 | 628 | ||
629 | static int skylake_card_late_probe(struct snd_soc_card *card) | ||
630 | { | ||
631 | struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); | ||
632 | struct skl_hdmi_pcm *pcm; | ||
633 | int err; | ||
634 | |||
635 | list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { | ||
636 | err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); | ||
637 | if (err < 0) | ||
638 | return err; | ||
639 | } | ||
640 | |||
641 | return 0; | ||
642 | } | ||
643 | |||
588 | /* skylake audio machine driver for SPT + NAU88L25 */ | 644 | /* skylake audio machine driver for SPT + NAU88L25 */ |
589 | static struct snd_soc_card skylake_audio_card = { | 645 | static struct snd_soc_card skylake_audio_card = { |
590 | .name = "sklnau8825adi", | 646 | .name = "sklnau8825adi", |
@@ -600,11 +656,21 @@ static struct snd_soc_card skylake_audio_card = { | |||
600 | .codec_conf = ssm4567_codec_conf, | 656 | .codec_conf = ssm4567_codec_conf, |
601 | .num_configs = ARRAY_SIZE(ssm4567_codec_conf), | 657 | .num_configs = ARRAY_SIZE(ssm4567_codec_conf), |
602 | .fully_routed = true, | 658 | .fully_routed = true, |
659 | .late_probe = skylake_card_late_probe, | ||
603 | }; | 660 | }; |
604 | 661 | ||
605 | static int skylake_audio_probe(struct platform_device *pdev) | 662 | static int skylake_audio_probe(struct platform_device *pdev) |
606 | { | 663 | { |
664 | struct skl_nau88125_private *ctx; | ||
665 | |||
666 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | ||
667 | if (!ctx) | ||
668 | return -ENOMEM; | ||
669 | |||
670 | INIT_LIST_HEAD(&ctx->hdmi_pcm_list); | ||
671 | |||
607 | skylake_audio_card.dev = &pdev->dev; | 672 | skylake_audio_card.dev = &pdev->dev; |
673 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); | ||
608 | 674 | ||
609 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); | 675 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); |
610 | } | 676 | } |
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 2016397a8e75..426b48233fdb 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c | |||
@@ -30,6 +30,16 @@ | |||
30 | 30 | ||
31 | static struct snd_soc_jack skylake_headset; | 31 | static struct snd_soc_jack skylake_headset; |
32 | 32 | ||
33 | struct skl_hdmi_pcm { | ||
34 | struct list_head head; | ||
35 | struct snd_soc_dai *codec_dai; | ||
36 | int device; | ||
37 | }; | ||
38 | |||
39 | struct skl_rt286_private { | ||
40 | struct list_head hdmi_pcm_list; | ||
41 | }; | ||
42 | |||
33 | enum { | 43 | enum { |
34 | SKL_DPCM_AUDIO_PB = 0, | 44 | SKL_DPCM_AUDIO_PB = 0, |
35 | SKL_DPCM_AUDIO_CP, | 45 | SKL_DPCM_AUDIO_CP, |
@@ -142,9 +152,20 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) | |||
142 | 152 | ||
143 | static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) | 153 | static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) |
144 | { | 154 | { |
155 | struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); | ||
145 | struct snd_soc_dai *dai = rtd->codec_dai; | 156 | struct snd_soc_dai *dai = rtd->codec_dai; |
157 | struct skl_hdmi_pcm *pcm; | ||
158 | |||
159 | pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); | ||
160 | if (!pcm) | ||
161 | return -ENOMEM; | ||
146 | 162 | ||
147 | return hdac_hdmi_jack_init(dai, SKL_DPCM_AUDIO_HDMI1_PB + dai->id); | 163 | pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id; |
164 | pcm->codec_dai = dai; | ||
165 | |||
166 | list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); | ||
167 | |||
168 | return 0; | ||
148 | } | 169 | } |
149 | 170 | ||
150 | static unsigned int rates[] = { | 171 | static unsigned int rates[] = { |
@@ -317,7 +338,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
317 | .platform_name = "0000:00:1f.3", | 338 | .platform_name = "0000:00:1f.3", |
318 | .init = NULL, | 339 | .init = NULL, |
319 | .dpcm_capture = 1, | 340 | .dpcm_capture = 1, |
320 | .ignore_suspend = 1, | ||
321 | .nonatomic = 1, | 341 | .nonatomic = 1, |
322 | .dynamic = 1, | 342 | .dynamic = 1, |
323 | }, | 343 | }, |
@@ -375,7 +395,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
375 | { | 395 | { |
376 | /* SSP0 - Codec */ | 396 | /* SSP0 - Codec */ |
377 | .name = "SSP0-Codec", | 397 | .name = "SSP0-Codec", |
378 | .be_id = 0, | 398 | .id = 0, |
379 | .cpu_dai_name = "SSP0 Pin", | 399 | .cpu_dai_name = "SSP0 Pin", |
380 | .platform_name = "0000:00:1f.3", | 400 | .platform_name = "0000:00:1f.3", |
381 | .no_pcm = 1, | 401 | .no_pcm = 1, |
@@ -393,7 +413,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
393 | }, | 413 | }, |
394 | { | 414 | { |
395 | .name = "dmic01", | 415 | .name = "dmic01", |
396 | .be_id = 1, | 416 | .id = 1, |
397 | .cpu_dai_name = "DMIC01 Pin", | 417 | .cpu_dai_name = "DMIC01 Pin", |
398 | .codec_name = "dmic-codec", | 418 | .codec_name = "dmic-codec", |
399 | .codec_dai_name = "dmic-hifi", | 419 | .codec_dai_name = "dmic-hifi", |
@@ -405,7 +425,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
405 | }, | 425 | }, |
406 | { | 426 | { |
407 | .name = "iDisp1", | 427 | .name = "iDisp1", |
408 | .be_id = 2, | 428 | .id = 2, |
409 | .cpu_dai_name = "iDisp1 Pin", | 429 | .cpu_dai_name = "iDisp1 Pin", |
410 | .codec_name = "ehdaudio0D2", | 430 | .codec_name = "ehdaudio0D2", |
411 | .codec_dai_name = "intel-hdmi-hifi1", | 431 | .codec_dai_name = "intel-hdmi-hifi1", |
@@ -416,7 +436,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
416 | }, | 436 | }, |
417 | { | 437 | { |
418 | .name = "iDisp2", | 438 | .name = "iDisp2", |
419 | .be_id = 3, | 439 | .id = 3, |
420 | .cpu_dai_name = "iDisp2 Pin", | 440 | .cpu_dai_name = "iDisp2 Pin", |
421 | .codec_name = "ehdaudio0D2", | 441 | .codec_name = "ehdaudio0D2", |
422 | .codec_dai_name = "intel-hdmi-hifi2", | 442 | .codec_dai_name = "intel-hdmi-hifi2", |
@@ -427,7 +447,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
427 | }, | 447 | }, |
428 | { | 448 | { |
429 | .name = "iDisp3", | 449 | .name = "iDisp3", |
430 | .be_id = 4, | 450 | .id = 4, |
431 | .cpu_dai_name = "iDisp3 Pin", | 451 | .cpu_dai_name = "iDisp3 Pin", |
432 | .codec_name = "ehdaudio0D2", | 452 | .codec_name = "ehdaudio0D2", |
433 | .codec_dai_name = "intel-hdmi-hifi3", | 453 | .codec_dai_name = "intel-hdmi-hifi3", |
@@ -438,6 +458,21 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { | |||
438 | }, | 458 | }, |
439 | }; | 459 | }; |
440 | 460 | ||
461 | static int skylake_card_late_probe(struct snd_soc_card *card) | ||
462 | { | ||
463 | struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); | ||
464 | struct skl_hdmi_pcm *pcm; | ||
465 | int err; | ||
466 | |||
467 | list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { | ||
468 | err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device); | ||
469 | if (err < 0) | ||
470 | return err; | ||
471 | } | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
441 | /* skylake audio machine driver for SPT + RT286S */ | 476 | /* skylake audio machine driver for SPT + RT286S */ |
442 | static struct snd_soc_card skylake_rt286 = { | 477 | static struct snd_soc_card skylake_rt286 = { |
443 | .name = "skylake-rt286", | 478 | .name = "skylake-rt286", |
@@ -451,11 +486,21 @@ static struct snd_soc_card skylake_rt286 = { | |||
451 | .dapm_routes = skylake_rt286_map, | 486 | .dapm_routes = skylake_rt286_map, |
452 | .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), | 487 | .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), |
453 | .fully_routed = true, | 488 | .fully_routed = true, |
489 | .late_probe = skylake_card_late_probe, | ||
454 | }; | 490 | }; |
455 | 491 | ||
456 | static int skylake_audio_probe(struct platform_device *pdev) | 492 | static int skylake_audio_probe(struct platform_device *pdev) |
457 | { | 493 | { |
494 | struct skl_rt286_private *ctx; | ||
495 | |||
496 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | ||
497 | if (!ctx) | ||
498 | return -ENOMEM; | ||
499 | |||
500 | INIT_LIST_HEAD(&ctx->hdmi_pcm_list); | ||
501 | |||
458 | skylake_rt286.dev = &pdev->dev; | 502 | skylake_rt286.dev = &pdev->dev; |
503 | snd_soc_card_set_drvdata(&skylake_rt286, ctx); | ||
459 | 504 | ||
460 | return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); | 505 | return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); |
461 | } | 506 | } |
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 4dcfb7e5ed70..8398cb227ba9 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h | |||
@@ -12,10 +12,19 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/kconfig.h> | ||
16 | #include <linux/stddef.h> | ||
15 | #include <linux/acpi.h> | 17 | #include <linux/acpi.h> |
16 | 18 | ||
17 | /* translation fron HID to I2C name, needed for DAI codec_name */ | 19 | /* translation fron HID to I2C name, needed for DAI codec_name */ |
20 | #if IS_ENABLED(CONFIG_ACPI) | ||
18 | const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); | 21 | const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); |
22 | #else | ||
23 | inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) | ||
24 | { | ||
25 | return NULL; | ||
26 | } | ||
27 | #endif | ||
19 | 28 | ||
20 | /* acpi match */ | 29 | /* acpi match */ |
21 | struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); | 30 | struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); |
diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index ac60f1301e21..91565229d074 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c | |||
@@ -1345,7 +1345,7 @@ int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | |||
1345 | return 0; | 1345 | return 0; |
1346 | 1346 | ||
1347 | /* wait for pause to complete before we reset the stream */ | 1347 | /* wait for pause to complete before we reset the stream */ |
1348 | while (stream->running && tries--) | 1348 | while (stream->running && --tries) |
1349 | msleep(1); | 1349 | msleep(1); |
1350 | if (!tries) { | 1350 | if (!tries) { |
1351 | dev_err(hsw->dev, "error: reset stream %d still running\n", | 1351 | dev_err(hsw->dev, "error: reset stream %d still running\n", |
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 1aa819c7e09b..994256b39b9c 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c | |||
@@ -445,7 +445,7 @@ static int create_adsp_page_table(struct snd_pcm_substream *substream, | |||
445 | 445 | ||
446 | pages = snd_sgbuf_aligned_pages(size); | 446 | pages = snd_sgbuf_aligned_pages(size); |
447 | 447 | ||
448 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", | 448 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zx pages %d\n", |
449 | dma_area, size, pages); | 449 | dma_area, size, pages); |
450 | 450 | ||
451 | for (i = 0; i < pages; i++) { | 451 | for (i = 0; i < pages; i++) { |
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 914b6dab9bea..c28f5d0e1d99 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile | |||
@@ -5,6 +5,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o | |||
5 | 5 | ||
6 | # Skylake IPC Support | 6 | # Skylake IPC Support |
7 | snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ | 7 | snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ |
8 | skl-sst.o | 8 | skl-sst.o bxt-sst.o |
9 | 9 | ||
10 | obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o | 10 | obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o |
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c new file mode 100644 index 000000000000..965ce40ce752 --- /dev/null +++ b/sound/soc/intel/skylake/bxt-sst.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * bxt-sst.c - DSP library functions for BXT platform | ||
3 | * | ||
4 | * Copyright (C) 2015-16 Intel Corp | ||
5 | * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> | ||
6 | * Jeeja KP <jeeja.kp@intel.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <linux/device.h> | ||
22 | |||
23 | #include "../common/sst-dsp.h" | ||
24 | #include "../common/sst-dsp-priv.h" | ||
25 | #include "skl-sst-ipc.h" | ||
26 | |||
27 | #define BXT_BASEFW_TIMEOUT 3000 | ||
28 | #define BXT_INIT_TIMEOUT 500 | ||
29 | #define BXT_IPC_PURGE_FW 0x01004000 | ||
30 | |||
31 | #define BXT_ROM_INIT 0x5 | ||
32 | #define BXT_ADSP_SRAM0_BASE 0x80000 | ||
33 | |||
34 | /* Firmware status window */ | ||
35 | #define BXT_ADSP_FW_STATUS BXT_ADSP_SRAM0_BASE | ||
36 | #define BXT_ADSP_ERROR_CODE (BXT_ADSP_FW_STATUS + 0x4) | ||
37 | |||
38 | #define BXT_ADSP_SRAM1_BASE 0xA0000 | ||
39 | |||
40 | static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) | ||
41 | { | ||
42 | return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); | ||
43 | } | ||
44 | |||
45 | static int sst_bxt_prepare_fw(struct sst_dsp *ctx, | ||
46 | const void *fwdata, u32 fwsize) | ||
47 | { | ||
48 | int stream_tag, ret, i; | ||
49 | u32 reg; | ||
50 | |||
51 | stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); | ||
52 | if (stream_tag < 0) { | ||
53 | dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n", | ||
54 | stream_tag); | ||
55 | return stream_tag; | ||
56 | } | ||
57 | |||
58 | ctx->dsp_ops.stream_tag = stream_tag; | ||
59 | memcpy(ctx->dmab.area, fwdata, fwsize); | ||
60 | |||
61 | /* Purge FW request */ | ||
62 | sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY | | ||
63 | BXT_IPC_PURGE_FW | (stream_tag - 1)); | ||
64 | |||
65 | ret = skl_dsp_enable_core(ctx); | ||
66 | if (ret < 0) { | ||
67 | dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); | ||
68 | ret = -EIO; | ||
69 | goto base_fw_load_failed; | ||
70 | } | ||
71 | |||
72 | for (i = BXT_INIT_TIMEOUT; i > 0; --i) { | ||
73 | reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); | ||
74 | |||
75 | if (reg & SKL_ADSP_REG_HIPCIE_DONE) { | ||
76 | sst_dsp_shim_update_bits_forced(ctx, | ||
77 | SKL_ADSP_REG_HIPCIE, | ||
78 | SKL_ADSP_REG_HIPCIE_DONE, | ||
79 | SKL_ADSP_REG_HIPCIE_DONE); | ||
80 | break; | ||
81 | } | ||
82 | mdelay(1); | ||
83 | } | ||
84 | if (!i) { | ||
85 | dev_info(ctx->dev, "Waiting for HIPCIE done, reg: 0x%x\n", reg); | ||
86 | sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCIE, | ||
87 | SKL_ADSP_REG_HIPCIE_DONE, | ||
88 | SKL_ADSP_REG_HIPCIE_DONE); | ||
89 | } | ||
90 | |||
91 | /* enable Interrupt */ | ||
92 | skl_ipc_int_enable(ctx); | ||
93 | skl_ipc_op_int_enable(ctx); | ||
94 | |||
95 | for (i = BXT_INIT_TIMEOUT; i > 0; --i) { | ||
96 | if (SKL_FW_INIT == | ||
97 | (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & | ||
98 | SKL_FW_STS_MASK)) { | ||
99 | |||
100 | dev_info(ctx->dev, "ROM loaded, continue FW loading\n"); | ||
101 | break; | ||
102 | } | ||
103 | mdelay(1); | ||
104 | } | ||
105 | if (!i) { | ||
106 | dev_err(ctx->dev, "Timeout for ROM init, HIPCIE: 0x%x\n", reg); | ||
107 | ret = -EIO; | ||
108 | goto base_fw_load_failed; | ||
109 | } | ||
110 | |||
111 | return ret; | ||
112 | |||
113 | base_fw_load_failed: | ||
114 | ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); | ||
115 | skl_dsp_disable_core(ctx); | ||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) | ||
120 | { | ||
121 | int ret; | ||
122 | |||
123 | ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); | ||
124 | ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, | ||
125 | BXT_ROM_INIT, BXT_BASEFW_TIMEOUT, "Firmware boot"); | ||
126 | |||
127 | ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); | ||
128 | ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static int bxt_load_base_firmware(struct sst_dsp *ctx) | ||
134 | { | ||
135 | const struct firmware *fw = NULL; | ||
136 | struct skl_sst *skl = ctx->thread_context; | ||
137 | int ret; | ||
138 | |||
139 | ret = request_firmware(&fw, ctx->fw_name, ctx->dev); | ||
140 | if (ret < 0) { | ||
141 | dev_err(ctx->dev, "Request firmware failed %d\n", ret); | ||
142 | goto sst_load_base_firmware_failed; | ||
143 | } | ||
144 | |||
145 | ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size); | ||
146 | /* Retry Enabling core and ROM load. Retry seemed to help */ | ||
147 | if (ret < 0) { | ||
148 | ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size); | ||
149 | if (ret < 0) { | ||
150 | dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); | ||
151 | goto sst_load_base_firmware_failed; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | ret = sst_transfer_fw_host_dma(ctx); | ||
156 | if (ret < 0) { | ||
157 | dev_err(ctx->dev, "Transfer firmware failed %d\n", ret); | ||
158 | dev_info(ctx->dev, "Error code=0x%x: FW status=0x%x\n", | ||
159 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), | ||
160 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); | ||
161 | |||
162 | skl_dsp_disable_core(ctx); | ||
163 | } else { | ||
164 | dev_dbg(ctx->dev, "Firmware download successful\n"); | ||
165 | ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, | ||
166 | msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); | ||
167 | if (ret == 0) { | ||
168 | dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n"); | ||
169 | skl_dsp_disable_core(ctx); | ||
170 | ret = -EIO; | ||
171 | } else { | ||
172 | skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); | ||
173 | ret = 0; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | sst_load_base_firmware_failed: | ||
178 | release_firmware(fw); | ||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | static int bxt_set_dsp_D0(struct sst_dsp *ctx) | ||
183 | { | ||
184 | struct skl_sst *skl = ctx->thread_context; | ||
185 | int ret; | ||
186 | |||
187 | skl->boot_complete = false; | ||
188 | |||
189 | ret = skl_dsp_enable_core(ctx); | ||
190 | if (ret < 0) { | ||
191 | dev_err(ctx->dev, "enable dsp core failed ret: %d\n", ret); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | /* enable interrupt */ | ||
196 | skl_ipc_int_enable(ctx); | ||
197 | skl_ipc_op_int_enable(ctx); | ||
198 | |||
199 | ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, | ||
200 | msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); | ||
201 | if (ret == 0) { | ||
202 | dev_err(ctx->dev, "ipc: error DSP boot timeout\n"); | ||
203 | dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", | ||
204 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), | ||
205 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); | ||
206 | return -EIO; | ||
207 | } | ||
208 | |||
209 | skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int bxt_set_dsp_D3(struct sst_dsp *ctx) | ||
214 | { | ||
215 | struct skl_ipc_dxstate_info dx; | ||
216 | struct skl_sst *skl = ctx->thread_context; | ||
217 | int ret = 0; | ||
218 | |||
219 | if (!is_skl_dsp_running(ctx)) | ||
220 | return ret; | ||
221 | |||
222 | dx.core_mask = SKL_DSP_CORE0_MASK; | ||
223 | dx.dx_mask = SKL_IPC_D3_MASK; | ||
224 | |||
225 | ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, | ||
226 | SKL_BASE_FW_MODULE_ID, &dx); | ||
227 | if (ret < 0) { | ||
228 | dev_err(ctx->dev, "Failed to set DSP to D3 state: %d\n", ret); | ||
229 | return ret; | ||
230 | } | ||
231 | |||
232 | ret = skl_dsp_disable_core(ctx); | ||
233 | if (ret < 0) { | ||
234 | dev_err(ctx->dev, "disbale dsp core failed: %d\n", ret); | ||
235 | ret = -EIO; | ||
236 | } | ||
237 | |||
238 | skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static struct skl_dsp_fw_ops bxt_fw_ops = { | ||
243 | .set_state_D0 = bxt_set_dsp_D0, | ||
244 | .set_state_D3 = bxt_set_dsp_D3, | ||
245 | .load_fw = bxt_load_base_firmware, | ||
246 | .get_fw_errcode = bxt_get_errorcode, | ||
247 | }; | ||
248 | |||
249 | static struct sst_ops skl_ops = { | ||
250 | .irq_handler = skl_dsp_sst_interrupt, | ||
251 | .write = sst_shim32_write, | ||
252 | .read = sst_shim32_read, | ||
253 | .ram_read = sst_memcpy_fromio_32, | ||
254 | .ram_write = sst_memcpy_toio_32, | ||
255 | .free = skl_dsp_free, | ||
256 | }; | ||
257 | |||
258 | static struct sst_dsp_device skl_dev = { | ||
259 | .thread = skl_dsp_irq_thread_handler, | ||
260 | .ops = &skl_ops, | ||
261 | }; | ||
262 | |||
263 | int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | ||
264 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, | ||
265 | struct skl_sst **dsp) | ||
266 | { | ||
267 | struct skl_sst *skl; | ||
268 | struct sst_dsp *sst; | ||
269 | int ret; | ||
270 | |||
271 | skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); | ||
272 | if (skl == NULL) | ||
273 | return -ENOMEM; | ||
274 | |||
275 | skl->dev = dev; | ||
276 | skl_dev.thread_context = skl; | ||
277 | |||
278 | skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); | ||
279 | if (!skl->dsp) { | ||
280 | dev_err(skl->dev, "skl_dsp_ctx_init failed\n"); | ||
281 | return -ENODEV; | ||
282 | } | ||
283 | |||
284 | sst = skl->dsp; | ||
285 | sst->fw_name = fw_name; | ||
286 | sst->dsp_ops = dsp_ops; | ||
287 | sst->fw_ops = bxt_fw_ops; | ||
288 | sst->addr.lpe = mmio_base; | ||
289 | sst->addr.shim = mmio_base; | ||
290 | |||
291 | sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), | ||
292 | SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); | ||
293 | |||
294 | ret = skl_ipc_init(dev, skl); | ||
295 | if (ret) | ||
296 | return ret; | ||
297 | |||
298 | skl->boot_complete = false; | ||
299 | init_waitqueue_head(&skl->boot_wait); | ||
300 | |||
301 | ret = sst->fw_ops.load_fw(sst); | ||
302 | if (ret < 0) { | ||
303 | dev_err(dev, "Load base fw failed: %x", ret); | ||
304 | return ret; | ||
305 | } | ||
306 | |||
307 | if (dsp) | ||
308 | *dsp = skl; | ||
309 | |||
310 | return 0; | ||
311 | } | ||
312 | EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); | ||
313 | |||
314 | |||
315 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) | ||
316 | { | ||
317 | skl_ipc_free(&ctx->ipc); | ||
318 | ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); | ||
319 | |||
320 | if (ctx->dsp->addr.lpe) | ||
321 | iounmap(ctx->dsp->addr.lpe); | ||
322 | |||
323 | ctx->dsp->ops->free(ctx->dsp); | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup); | ||
326 | |||
327 | MODULE_LICENSE("GPL v2"); | ||
328 | MODULE_DESCRIPTION("Intel Broxton IPC driver"); | ||
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 79c5089b85d6..226db84ba20f 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c | |||
@@ -72,6 +72,105 @@ static void skl_dsp_enable_notification(struct skl_sst *ctx, bool enable) | |||
72 | skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask); | 72 | skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)&mask); |
73 | } | 73 | } |
74 | 74 | ||
75 | static int skl_dsp_setup_spib(struct device *dev, unsigned int size, | ||
76 | int stream_tag, int enable) | ||
77 | { | ||
78 | struct hdac_ext_bus *ebus = dev_get_drvdata(dev); | ||
79 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
80 | struct hdac_stream *stream = snd_hdac_get_stream(bus, | ||
81 | SNDRV_PCM_STREAM_PLAYBACK, stream_tag); | ||
82 | struct hdac_ext_stream *estream; | ||
83 | |||
84 | if (!stream) | ||
85 | return -EINVAL; | ||
86 | |||
87 | estream = stream_to_hdac_ext_stream(stream); | ||
88 | /* enable/disable SPIB for this hdac stream */ | ||
89 | snd_hdac_ext_stream_spbcap_enable(ebus, enable, stream->index); | ||
90 | |||
91 | /* set the spib value */ | ||
92 | snd_hdac_ext_stream_set_spib(ebus, estream, size); | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | static int skl_dsp_prepare(struct device *dev, unsigned int format, | ||
98 | unsigned int size, struct snd_dma_buffer *dmab) | ||
99 | { | ||
100 | struct hdac_ext_bus *ebus = dev_get_drvdata(dev); | ||
101 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
102 | struct hdac_ext_stream *estream; | ||
103 | struct hdac_stream *stream; | ||
104 | struct snd_pcm_substream substream; | ||
105 | int ret; | ||
106 | |||
107 | if (!bus) | ||
108 | return -ENODEV; | ||
109 | |||
110 | memset(&substream, 0, sizeof(substream)); | ||
111 | substream.stream = SNDRV_PCM_STREAM_PLAYBACK; | ||
112 | |||
113 | estream = snd_hdac_ext_stream_assign(ebus, &substream, | ||
114 | HDAC_EXT_STREAM_TYPE_HOST); | ||
115 | if (!estream) | ||
116 | return -ENODEV; | ||
117 | |||
118 | stream = hdac_stream(estream); | ||
119 | |||
120 | /* assign decouple host dma channel */ | ||
121 | ret = snd_hdac_dsp_prepare(stream, format, size, dmab); | ||
122 | if (ret < 0) | ||
123 | return ret; | ||
124 | |||
125 | skl_dsp_setup_spib(dev, size, stream->stream_tag, true); | ||
126 | |||
127 | return stream->stream_tag; | ||
128 | } | ||
129 | |||
130 | static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag) | ||
131 | { | ||
132 | struct hdac_ext_bus *ebus = dev_get_drvdata(dev); | ||
133 | struct hdac_stream *stream; | ||
134 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
135 | |||
136 | if (!bus) | ||
137 | return -ENODEV; | ||
138 | |||
139 | stream = snd_hdac_get_stream(bus, | ||
140 | SNDRV_PCM_STREAM_PLAYBACK, stream_tag); | ||
141 | if (!stream) | ||
142 | return -EINVAL; | ||
143 | |||
144 | snd_hdac_dsp_trigger(stream, start); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int skl_dsp_cleanup(struct device *dev, | ||
150 | struct snd_dma_buffer *dmab, int stream_tag) | ||
151 | { | ||
152 | struct hdac_ext_bus *ebus = dev_get_drvdata(dev); | ||
153 | struct hdac_stream *stream; | ||
154 | struct hdac_ext_stream *estream; | ||
155 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
156 | |||
157 | if (!bus) | ||
158 | return -ENODEV; | ||
159 | |||
160 | stream = snd_hdac_get_stream(bus, | ||
161 | SNDRV_PCM_STREAM_PLAYBACK, stream_tag); | ||
162 | if (!stream) | ||
163 | return -EINVAL; | ||
164 | |||
165 | estream = stream_to_hdac_ext_stream(stream); | ||
166 | skl_dsp_setup_spib(dev, 0, stream_tag, false); | ||
167 | snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST); | ||
168 | |||
169 | snd_hdac_dsp_cleanup(stream, dmab); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
75 | static struct skl_dsp_loader_ops skl_get_loader_ops(void) | 174 | static struct skl_dsp_loader_ops skl_get_loader_ops(void) |
76 | { | 175 | { |
77 | struct skl_dsp_loader_ops loader_ops; | 176 | struct skl_dsp_loader_ops loader_ops; |
@@ -84,6 +183,21 @@ static struct skl_dsp_loader_ops skl_get_loader_ops(void) | |||
84 | return loader_ops; | 183 | return loader_ops; |
85 | }; | 184 | }; |
86 | 185 | ||
186 | static struct skl_dsp_loader_ops bxt_get_loader_ops(void) | ||
187 | { | ||
188 | struct skl_dsp_loader_ops loader_ops; | ||
189 | |||
190 | memset(&loader_ops, 0, sizeof(loader_ops)); | ||
191 | |||
192 | loader_ops.alloc_dma_buf = skl_alloc_dma_buf; | ||
193 | loader_ops.free_dma_buf = skl_free_dma_buf; | ||
194 | loader_ops.prepare = skl_dsp_prepare; | ||
195 | loader_ops.trigger = skl_dsp_trigger; | ||
196 | loader_ops.cleanup = skl_dsp_cleanup; | ||
197 | |||
198 | return loader_ops; | ||
199 | }; | ||
200 | |||
87 | static const struct skl_dsp_ops dsp_ops[] = { | 201 | static const struct skl_dsp_ops dsp_ops[] = { |
88 | { | 202 | { |
89 | .id = 0x9d70, | 203 | .id = 0x9d70, |
@@ -91,6 +205,12 @@ static const struct skl_dsp_ops dsp_ops[] = { | |||
91 | .init = skl_sst_dsp_init, | 205 | .init = skl_sst_dsp_init, |
92 | .cleanup = skl_sst_dsp_cleanup | 206 | .cleanup = skl_sst_dsp_cleanup |
93 | }, | 207 | }, |
208 | { | ||
209 | .id = 0x5a98, | ||
210 | .loader_ops = bxt_get_loader_ops, | ||
211 | .init = bxt_sst_dsp_init, | ||
212 | .cleanup = bxt_sst_dsp_cleanup | ||
213 | }, | ||
94 | }; | 214 | }; |
95 | 215 | ||
96 | static int skl_get_dsp_ops(int pci_id) | 216 | static int skl_get_dsp_ops(int pci_id) |
@@ -744,7 +864,7 @@ int skl_init_module(struct skl_sst *ctx, | |||
744 | return ret; | 864 | return ret; |
745 | } | 865 | } |
746 | mconfig->m_state = SKL_MODULE_INIT_DONE; | 866 | mconfig->m_state = SKL_MODULE_INIT_DONE; |
747 | 867 | kfree(param_data); | |
748 | return ret; | 868 | return ret; |
749 | } | 869 | } |
750 | 870 | ||
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 14d1916ea9f8..7d73648e5f9a 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c | |||
@@ -25,11 +25,12 @@ static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, | |||
25 | 25 | ||
26 | #define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" | 26 | #define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" |
27 | 27 | ||
28 | void *skl_nhlt_init(struct device *dev) | 28 | struct nhlt_acpi_table *skl_nhlt_init(struct device *dev) |
29 | { | 29 | { |
30 | acpi_handle handle; | 30 | acpi_handle handle; |
31 | union acpi_object *obj; | 31 | union acpi_object *obj; |
32 | struct nhlt_resource_desc *nhlt_ptr = NULL; | 32 | struct nhlt_resource_desc *nhlt_ptr = NULL; |
33 | struct nhlt_acpi_table *nhlt_table = NULL; | ||
33 | 34 | ||
34 | if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { | 35 | if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { |
35 | dev_err(dev, "Requested NHLT device not found\n"); | 36 | dev_err(dev, "Requested NHLT device not found\n"); |
@@ -39,18 +40,20 @@ void *skl_nhlt_init(struct device *dev) | |||
39 | obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL); | 40 | obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL); |
40 | if (obj && obj->type == ACPI_TYPE_BUFFER) { | 41 | if (obj && obj->type == ACPI_TYPE_BUFFER) { |
41 | nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; | 42 | nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; |
42 | 43 | nhlt_table = (struct nhlt_acpi_table *) | |
43 | return memremap(nhlt_ptr->min_addr, nhlt_ptr->length, | 44 | memremap(nhlt_ptr->min_addr, nhlt_ptr->length, |
44 | MEMREMAP_WB); | 45 | MEMREMAP_WB); |
46 | ACPI_FREE(obj); | ||
47 | return nhlt_table; | ||
45 | } | 48 | } |
46 | 49 | ||
47 | dev_err(dev, "device specific method to extract NHLT blob failed\n"); | 50 | dev_err(dev, "device specific method to extract NHLT blob failed\n"); |
48 | return NULL; | 51 | return NULL; |
49 | } | 52 | } |
50 | 53 | ||
51 | void skl_nhlt_free(void *addr) | 54 | void skl_nhlt_free(struct nhlt_acpi_table *nhlt) |
52 | { | 55 | { |
53 | memunmap(addr); | 56 | memunmap((void *) nhlt); |
54 | } | 57 | } |
55 | 58 | ||
56 | static struct nhlt_specific_cfg *skl_get_specific_cfg( | 59 | static struct nhlt_specific_cfg *skl_get_specific_cfg( |
@@ -120,7 +123,7 @@ struct nhlt_specific_cfg | |||
120 | struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); | 123 | struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); |
121 | struct device *dev = bus->dev; | 124 | struct device *dev = bus->dev; |
122 | struct nhlt_specific_cfg *sp_config; | 125 | struct nhlt_specific_cfg *sp_config; |
123 | struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; | 126 | struct nhlt_acpi_table *nhlt = skl->nhlt; |
124 | u16 bps = (s_fmt == 16) ? 16 : 32; | 127 | u16 bps = (s_fmt == 16) ? 16 : 32; |
125 | u8 j; | 128 | u8 j; |
126 | 129 | ||
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index dab0900eef26..7c81b31748ff 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c | |||
@@ -51,7 +51,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { | |||
51 | .rate_min = 8000, | 51 | .rate_min = 8000, |
52 | .rate_max = 48000, | 52 | .rate_max = 48000, |
53 | .channels_min = 1, | 53 | .channels_min = 1, |
54 | .channels_max = HDA_QUAD, | 54 | .channels_max = 8, |
55 | .buffer_bytes_max = AZX_MAX_BUF_SIZE, | 55 | .buffer_bytes_max = AZX_MAX_BUF_SIZE, |
56 | .period_bytes_min = 128, | 56 | .period_bytes_min = 128, |
57 | .period_bytes_max = AZX_MAX_BUF_SIZE / 2, | 57 | .period_bytes_max = AZX_MAX_BUF_SIZE / 2, |
@@ -213,7 +213,7 @@ static int skl_be_prepare(struct snd_pcm_substream *substream, | |||
213 | struct skl_sst *ctx = skl->skl_sst; | 213 | struct skl_sst *ctx = skl->skl_sst; |
214 | struct skl_module_cfg *mconfig; | 214 | struct skl_module_cfg *mconfig; |
215 | 215 | ||
216 | if ((dai->playback_active > 1) || (dai->capture_active > 1)) | 216 | if (dai->playback_widget->power || dai->capture_widget->power) |
217 | return 0; | 217 | return 0; |
218 | 218 | ||
219 | mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); | 219 | mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); |
@@ -402,23 +402,33 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, | |||
402 | struct skl_module_cfg *mconfig; | 402 | struct skl_module_cfg *mconfig; |
403 | struct hdac_ext_bus *ebus = get_bus_ctx(substream); | 403 | struct hdac_ext_bus *ebus = get_bus_ctx(substream); |
404 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); | 404 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); |
405 | struct snd_soc_dapm_widget *w; | ||
405 | int ret; | 406 | int ret; |
406 | 407 | ||
407 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); | 408 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); |
408 | if (!mconfig) | 409 | if (!mconfig) |
409 | return -EIO; | 410 | return -EIO; |
410 | 411 | ||
412 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
413 | w = dai->playback_widget; | ||
414 | else | ||
415 | w = dai->capture_widget; | ||
416 | |||
411 | switch (cmd) { | 417 | switch (cmd) { |
412 | case SNDRV_PCM_TRIGGER_RESUME: | 418 | case SNDRV_PCM_TRIGGER_RESUME: |
413 | skl_pcm_prepare(substream, dai); | 419 | if (!w->ignore_suspend) { |
414 | /* | 420 | skl_pcm_prepare(substream, dai); |
415 | * enable DMA Resume enable bit for the stream, set the dpib | 421 | /* |
416 | * & lpib position to resune before starting the DMA | 422 | * enable DMA Resume enable bit for the stream, set the |
417 | */ | 423 | * dpib & lpib position to resume before starting the |
418 | snd_hdac_ext_stream_drsm_enable(ebus, true, | 424 | * DMA |
419 | hdac_stream(stream)->index); | 425 | */ |
420 | snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); | 426 | snd_hdac_ext_stream_drsm_enable(ebus, true, |
421 | snd_hdac_ext_stream_set_lpib(stream, stream->lpib); | 427 | hdac_stream(stream)->index); |
428 | snd_hdac_ext_stream_set_dpibr(ebus, stream, | ||
429 | stream->dpib); | ||
430 | snd_hdac_ext_stream_set_lpib(stream, stream->lpib); | ||
431 | } | ||
422 | 432 | ||
423 | case SNDRV_PCM_TRIGGER_START: | 433 | case SNDRV_PCM_TRIGGER_START: |
424 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 434 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
@@ -448,7 +458,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, | |||
448 | return ret; | 458 | return ret; |
449 | 459 | ||
450 | ret = skl_decoupled_trigger(substream, cmd); | 460 | ret = skl_decoupled_trigger(substream, cmd); |
451 | if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) { | 461 | if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { |
452 | /* save the dpib and lpib positions */ | 462 | /* save the dpib and lpib positions */ |
453 | stream->dpib = readl(ebus->bus.remap_addr + | 463 | stream->dpib = readl(ebus->bus.remap_addr + |
454 | AZX_REG_VS_SDXDPIB_XBASE + | 464 | AZX_REG_VS_SDXDPIB_XBASE + |
@@ -523,7 +533,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, | |||
523 | if (!link) | 533 | if (!link) |
524 | return -EINVAL; | 534 | return -EINVAL; |
525 | 535 | ||
526 | snd_hdac_ext_bus_link_power_up(link); | ||
527 | snd_hdac_ext_link_stream_reset(link_dev); | 536 | snd_hdac_ext_link_stream_reset(link_dev); |
528 | 537 | ||
529 | snd_hdac_ext_link_stream_setup(link_dev, format_val); | 538 | snd_hdac_ext_link_stream_setup(link_dev, format_val); |
@@ -682,7 +691,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
682 | .playback = { | 691 | .playback = { |
683 | .stream_name = "HDMI1 Playback", | 692 | .stream_name = "HDMI1 Playback", |
684 | .channels_min = HDA_STEREO, | 693 | .channels_min = HDA_STEREO, |
685 | .channels_max = HDA_STEREO, | 694 | .channels_max = 8, |
686 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | 695 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
687 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | 696 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | |
688 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | 697 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | |
@@ -697,7 +706,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
697 | .playback = { | 706 | .playback = { |
698 | .stream_name = "HDMI2 Playback", | 707 | .stream_name = "HDMI2 Playback", |
699 | .channels_min = HDA_STEREO, | 708 | .channels_min = HDA_STEREO, |
700 | .channels_max = HDA_STEREO, | 709 | .channels_max = 8, |
701 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | 710 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
702 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | 711 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | |
703 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | 712 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | |
@@ -712,7 +721,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
712 | .playback = { | 721 | .playback = { |
713 | .stream_name = "HDMI3 Playback", | 722 | .stream_name = "HDMI3 Playback", |
714 | .channels_min = HDA_STEREO, | 723 | .channels_min = HDA_STEREO, |
715 | .channels_max = HDA_STEREO, | 724 | .channels_max = 8, |
716 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | 725 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
717 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | 726 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | |
718 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | 727 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | |
@@ -760,12 +769,84 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
760 | }, | 769 | }, |
761 | }, | 770 | }, |
762 | { | 771 | { |
772 | .name = "SSP2 Pin", | ||
773 | .ops = &skl_be_ssp_dai_ops, | ||
774 | .playback = { | ||
775 | .stream_name = "ssp2 Tx", | ||
776 | .channels_min = HDA_STEREO, | ||
777 | .channels_max = HDA_STEREO, | ||
778 | .rates = SNDRV_PCM_RATE_48000, | ||
779 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
780 | }, | ||
781 | .capture = { | ||
782 | .stream_name = "ssp2 Rx", | ||
783 | .channels_min = HDA_STEREO, | ||
784 | .channels_max = HDA_STEREO, | ||
785 | .rates = SNDRV_PCM_RATE_48000, | ||
786 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
787 | }, | ||
788 | }, | ||
789 | { | ||
790 | .name = "SSP3 Pin", | ||
791 | .ops = &skl_be_ssp_dai_ops, | ||
792 | .playback = { | ||
793 | .stream_name = "ssp3 Tx", | ||
794 | .channels_min = HDA_STEREO, | ||
795 | .channels_max = HDA_STEREO, | ||
796 | .rates = SNDRV_PCM_RATE_48000, | ||
797 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
798 | }, | ||
799 | .capture = { | ||
800 | .stream_name = "ssp3 Rx", | ||
801 | .channels_min = HDA_STEREO, | ||
802 | .channels_max = HDA_STEREO, | ||
803 | .rates = SNDRV_PCM_RATE_48000, | ||
804 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
805 | }, | ||
806 | }, | ||
807 | { | ||
808 | .name = "SSP4 Pin", | ||
809 | .ops = &skl_be_ssp_dai_ops, | ||
810 | .playback = { | ||
811 | .stream_name = "ssp4 Tx", | ||
812 | .channels_min = HDA_STEREO, | ||
813 | .channels_max = HDA_STEREO, | ||
814 | .rates = SNDRV_PCM_RATE_48000, | ||
815 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
816 | }, | ||
817 | .capture = { | ||
818 | .stream_name = "ssp4 Rx", | ||
819 | .channels_min = HDA_STEREO, | ||
820 | .channels_max = HDA_STEREO, | ||
821 | .rates = SNDRV_PCM_RATE_48000, | ||
822 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
823 | }, | ||
824 | }, | ||
825 | { | ||
826 | .name = "SSP5 Pin", | ||
827 | .ops = &skl_be_ssp_dai_ops, | ||
828 | .playback = { | ||
829 | .stream_name = "ssp5 Tx", | ||
830 | .channels_min = HDA_STEREO, | ||
831 | .channels_max = HDA_STEREO, | ||
832 | .rates = SNDRV_PCM_RATE_48000, | ||
833 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
834 | }, | ||
835 | .capture = { | ||
836 | .stream_name = "ssp5 Rx", | ||
837 | .channels_min = HDA_STEREO, | ||
838 | .channels_max = HDA_STEREO, | ||
839 | .rates = SNDRV_PCM_RATE_48000, | ||
840 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
841 | }, | ||
842 | }, | ||
843 | { | ||
763 | .name = "iDisp1 Pin", | 844 | .name = "iDisp1 Pin", |
764 | .ops = &skl_link_dai_ops, | 845 | .ops = &skl_link_dai_ops, |
765 | .playback = { | 846 | .playback = { |
766 | .stream_name = "iDisp1 Tx", | 847 | .stream_name = "iDisp1 Tx", |
767 | .channels_min = HDA_STEREO, | 848 | .channels_min = HDA_STEREO, |
768 | .channels_max = HDA_STEREO, | 849 | .channels_max = 8, |
769 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, | 850 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, |
770 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | | 851 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | |
771 | SNDRV_PCM_FMTBIT_S24_LE, | 852 | SNDRV_PCM_FMTBIT_S24_LE, |
@@ -777,7 +858,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
777 | .playback = { | 858 | .playback = { |
778 | .stream_name = "iDisp2 Tx", | 859 | .stream_name = "iDisp2 Tx", |
779 | .channels_min = HDA_STEREO, | 860 | .channels_min = HDA_STEREO, |
780 | .channels_max = HDA_STEREO, | 861 | .channels_max = 8, |
781 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| | 862 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| |
782 | SNDRV_PCM_RATE_48000, | 863 | SNDRV_PCM_RATE_48000, |
783 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | | 864 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | |
@@ -790,7 +871,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { | |||
790 | .playback = { | 871 | .playback = { |
791 | .stream_name = "iDisp3 Tx", | 872 | .stream_name = "iDisp3 Tx", |
792 | .channels_min = HDA_STEREO, | 873 | .channels_min = HDA_STEREO, |
793 | .channels_max = HDA_STEREO, | 874 | .channels_max = 8, |
794 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| | 875 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| |
795 | SNDRV_PCM_RATE_48000, | 876 | SNDRV_PCM_RATE_48000, |
796 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | | 877 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | |
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index a5267e8a96e0..13c19855ee1a 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c | |||
@@ -336,6 +336,9 @@ void skl_dsp_free(struct sst_dsp *dsp) | |||
336 | skl_ipc_int_disable(dsp); | 336 | skl_ipc_int_disable(dsp); |
337 | 337 | ||
338 | free_irq(dsp->irq, dsp); | 338 | free_irq(dsp->irq, dsp); |
339 | skl_ipc_op_int_disable(dsp); | ||
340 | skl_ipc_int_disable(dsp); | ||
341 | |||
339 | skl_dsp_disable_core(dsp); | 342 | skl_dsp_disable_core(dsp); |
340 | } | 343 | } |
341 | EXPORT_SYMBOL_GPL(skl_dsp_free); | 344 | EXPORT_SYMBOL_GPL(skl_dsp_free); |
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index b6e310d49dd6..deabe7308d3b 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h | |||
@@ -118,16 +118,25 @@ struct skl_dsp_fw_ops { | |||
118 | int (*set_state_D0)(struct sst_dsp *ctx); | 118 | int (*set_state_D0)(struct sst_dsp *ctx); |
119 | int (*set_state_D3)(struct sst_dsp *ctx); | 119 | int (*set_state_D3)(struct sst_dsp *ctx); |
120 | unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); | 120 | unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); |
121 | int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name); | 121 | int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); |
122 | int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); | 122 | int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); |
123 | 123 | ||
124 | }; | 124 | }; |
125 | 125 | ||
126 | struct skl_dsp_loader_ops { | 126 | struct skl_dsp_loader_ops { |
127 | int stream_tag; | ||
128 | |||
127 | int (*alloc_dma_buf)(struct device *dev, | 129 | int (*alloc_dma_buf)(struct device *dev, |
128 | struct snd_dma_buffer *dmab, size_t size); | 130 | struct snd_dma_buffer *dmab, size_t size); |
129 | int (*free_dma_buf)(struct device *dev, | 131 | int (*free_dma_buf)(struct device *dev, |
130 | struct snd_dma_buffer *dmab); | 132 | struct snd_dma_buffer *dmab); |
133 | int (*prepare)(struct device *dev, unsigned int format, | ||
134 | unsigned int byte_size, | ||
135 | struct snd_dma_buffer *bufp); | ||
136 | int (*trigger)(struct device *dev, bool start, int stream_tag); | ||
137 | |||
138 | int (*cleanup)(struct device *dev, struct snd_dma_buffer *dmab, | ||
139 | int stream_tag); | ||
131 | }; | 140 | }; |
132 | 141 | ||
133 | struct skl_load_module_info { | 142 | struct skl_load_module_info { |
@@ -160,6 +169,10 @@ int skl_dsp_boot(struct sst_dsp *ctx); | |||
160 | int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | 169 | int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, |
161 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, | 170 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, |
162 | struct skl_sst **dsp); | 171 | struct skl_sst **dsp); |
172 | int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | ||
173 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, | ||
174 | struct skl_sst **dsp); | ||
163 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); | 175 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); |
176 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); | ||
164 | 177 | ||
165 | #endif /*__SKL_SST_DSP_H__*/ | 178 | #endif /*__SKL_SST_DSP_H__*/ |
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 348a734f8e24..13ec8d53b526 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
23 | #include <linux/uuid.h> | ||
23 | #include "../common/sst-dsp.h" | 24 | #include "../common/sst-dsp.h" |
24 | #include "../common/sst-dsp-priv.h" | 25 | #include "../common/sst-dsp-priv.h" |
25 | #include "../common/sst-ipc.h" | 26 | #include "../common/sst-ipc.h" |
@@ -304,14 +305,16 @@ static int skl_transfer_module(struct sst_dsp *ctx, | |||
304 | return ret; | 305 | return ret; |
305 | } | 306 | } |
306 | 307 | ||
307 | static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid) | 308 | static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) |
308 | { | 309 | { |
309 | struct skl_module_table *module_entry = NULL; | 310 | struct skl_module_table *module_entry = NULL; |
310 | int ret = 0; | 311 | int ret = 0; |
311 | char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ | 312 | char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ |
313 | uuid_le *uuid_mod; | ||
312 | 314 | ||
313 | snprintf(mod_name, sizeof(mod_name), "%s%s%s", | 315 | uuid_mod = (uuid_le *)guid; |
314 | "intel/dsp_fw_", guid, ".bin"); | 316 | snprintf(mod_name, sizeof(mod_name), "%s%pUL%s", |
317 | "intel/dsp_fw_", uuid_mod, ".bin"); | ||
315 | 318 | ||
316 | module_entry = skl_module_get_from_id(ctx, mod_id); | 319 | module_entry = skl_module_get_from_id(ctx, mod_id); |
317 | if (module_entry == NULL) { | 320 | if (module_entry == NULL) { |
@@ -451,6 +454,10 @@ void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) | |||
451 | skl_clear_module_table(ctx->dsp); | 454 | skl_clear_module_table(ctx->dsp); |
452 | skl_ipc_free(&ctx->ipc); | 455 | skl_ipc_free(&ctx->ipc); |
453 | ctx->dsp->ops->free(ctx->dsp); | 456 | ctx->dsp->ops->free(ctx->dsp); |
457 | if (ctx->boot_complete) { | ||
458 | ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); | ||
459 | skl_cldma_int_disable(ctx->dsp); | ||
460 | } | ||
454 | } | 461 | } |
455 | EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); | 462 | EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); |
456 | 463 | ||
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 545b4e77b8aa..3e036b0349b9 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c | |||
@@ -154,13 +154,32 @@ static void skl_dump_mconfig(struct skl_sst *ctx, | |||
154 | dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); | 154 | dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); |
155 | } | 155 | } |
156 | 156 | ||
157 | static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) | ||
158 | { | ||
159 | int slot_map = 0xFFFFFFFF; | ||
160 | int start_slot = 0; | ||
161 | int i; | ||
162 | |||
163 | for (i = 0; i < chs; i++) { | ||
164 | /* | ||
165 | * For 2 channels with starting slot as 0, slot map will | ||
166 | * look like 0xFFFFFF10. | ||
167 | */ | ||
168 | slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); | ||
169 | start_slot++; | ||
170 | } | ||
171 | fmt->ch_map = slot_map; | ||
172 | } | ||
173 | |||
157 | static void skl_tplg_update_params(struct skl_module_fmt *fmt, | 174 | static void skl_tplg_update_params(struct skl_module_fmt *fmt, |
158 | struct skl_pipe_params *params, int fixup) | 175 | struct skl_pipe_params *params, int fixup) |
159 | { | 176 | { |
160 | if (fixup & SKL_RATE_FIXUP_MASK) | 177 | if (fixup & SKL_RATE_FIXUP_MASK) |
161 | fmt->s_freq = params->s_freq; | 178 | fmt->s_freq = params->s_freq; |
162 | if (fixup & SKL_CH_FIXUP_MASK) | 179 | if (fixup & SKL_CH_FIXUP_MASK) { |
163 | fmt->channels = params->ch; | 180 | fmt->channels = params->ch; |
181 | skl_tplg_update_chmap(fmt, fmt->channels); | ||
182 | } | ||
164 | if (fixup & SKL_FMT_FIXUP_MASK) { | 183 | if (fixup & SKL_FMT_FIXUP_MASK) { |
165 | fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); | 184 | fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); |
166 | 185 | ||
@@ -239,6 +258,7 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, | |||
239 | { | 258 | { |
240 | int multiplier = 1; | 259 | int multiplier = 1; |
241 | struct skl_module_fmt *in_fmt, *out_fmt; | 260 | struct skl_module_fmt *in_fmt, *out_fmt; |
261 | int in_rate, out_rate; | ||
242 | 262 | ||
243 | 263 | ||
244 | /* Since fixups is applied to pin 0 only, ibs, obs needs | 264 | /* Since fixups is applied to pin 0 only, ibs, obs needs |
@@ -249,15 +269,24 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, | |||
249 | 269 | ||
250 | if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) | 270 | if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) |
251 | multiplier = 5; | 271 | multiplier = 5; |
252 | mcfg->ibs = (in_fmt->s_freq / 1000) * | 272 | |
253 | (mcfg->in_fmt->channels) * | 273 | if (in_fmt->s_freq % 1000) |
254 | (mcfg->in_fmt->bit_depth >> 3) * | 274 | in_rate = (in_fmt->s_freq / 1000) + 1; |
255 | multiplier; | 275 | else |
256 | 276 | in_rate = (in_fmt->s_freq / 1000); | |
257 | mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * | 277 | |
258 | (mcfg->out_fmt->channels) * | 278 | mcfg->ibs = in_rate * (mcfg->in_fmt->channels) * |
259 | (mcfg->out_fmt->bit_depth >> 3) * | 279 | (mcfg->in_fmt->bit_depth >> 3) * |
260 | multiplier; | 280 | multiplier; |
281 | |||
282 | if (mcfg->out_fmt->s_freq % 1000) | ||
283 | out_rate = (mcfg->out_fmt->s_freq / 1000) + 1; | ||
284 | else | ||
285 | out_rate = (mcfg->out_fmt->s_freq / 1000); | ||
286 | |||
287 | mcfg->obs = out_rate * (mcfg->out_fmt->channels) * | ||
288 | (mcfg->out_fmt->bit_depth >> 3) * | ||
289 | multiplier; | ||
261 | } | 290 | } |
262 | 291 | ||
263 | static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, | 292 | static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, |
@@ -485,11 +514,15 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
485 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) | 514 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) |
486 | return -ENOMEM; | 515 | return -ENOMEM; |
487 | 516 | ||
517 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
518 | |||
488 | if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { | 519 | if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { |
489 | ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, | 520 | ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, |
490 | mconfig->id.module_id, mconfig->guid); | 521 | mconfig->id.module_id, mconfig->guid); |
491 | if (ret < 0) | 522 | if (ret < 0) |
492 | return ret; | 523 | return ret; |
524 | |||
525 | mconfig->m_state = SKL_MODULE_LOADED; | ||
493 | } | 526 | } |
494 | 527 | ||
495 | /* update blob if blob is null for be with default value */ | 528 | /* update blob if blob is null for be with default value */ |
@@ -509,7 +542,6 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
509 | ret = skl_tplg_set_module_params(w, ctx); | 542 | ret = skl_tplg_set_module_params(w, ctx); |
510 | if (ret < 0) | 543 | if (ret < 0) |
511 | return ret; | 544 | return ret; |
512 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
513 | } | 545 | } |
514 | 546 | ||
515 | return 0; | 547 | return 0; |
@@ -524,7 +556,8 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, | |||
524 | list_for_each_entry(w_module, &pipe->w_list, node) { | 556 | list_for_each_entry(w_module, &pipe->w_list, node) { |
525 | mconfig = w_module->w->priv; | 557 | mconfig = w_module->w->priv; |
526 | 558 | ||
527 | if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod) | 559 | if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod && |
560 | mconfig->m_state > SKL_MODULE_UNINIT) | ||
528 | return ctx->dsp->fw_ops.unload_mod(ctx->dsp, | 561 | return ctx->dsp->fw_ops.unload_mod(ctx->dsp, |
529 | mconfig->id.module_id); | 562 | mconfig->id.module_id); |
530 | } | 563 | } |
@@ -558,6 +591,9 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
558 | if (!skl_is_pipe_mem_avail(skl, mconfig)) | 591 | if (!skl_is_pipe_mem_avail(skl, mconfig)) |
559 | return -ENOMEM; | 592 | return -ENOMEM; |
560 | 593 | ||
594 | skl_tplg_alloc_pipe_mem(skl, mconfig); | ||
595 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
596 | |||
561 | /* | 597 | /* |
562 | * Create a list of modules for pipe. | 598 | * Create a list of modules for pipe. |
563 | * This list contains modules from source to sink | 599 | * This list contains modules from source to sink |
@@ -601,9 +637,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
601 | src_module = dst_module; | 637 | src_module = dst_module; |
602 | } | 638 | } |
603 | 639 | ||
604 | skl_tplg_alloc_pipe_mem(skl, mconfig); | ||
605 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
606 | |||
607 | return 0; | 640 | return 0; |
608 | } | 641 | } |
609 | 642 | ||
@@ -1550,6 +1583,8 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, | |||
1550 | return -ENOMEM; | 1583 | return -ENOMEM; |
1551 | 1584 | ||
1552 | w->priv = mconfig; | 1585 | w->priv = mconfig; |
1586 | memcpy(&mconfig->guid, &dfw_config->uuid, 16); | ||
1587 | |||
1553 | mconfig->id.module_id = dfw_config->module_id; | 1588 | mconfig->id.module_id = dfw_config->module_id; |
1554 | mconfig->id.instance_id = dfw_config->instance_id; | 1589 | mconfig->id.instance_id = dfw_config->instance_id; |
1555 | mconfig->mcps = dfw_config->max_mcps; | 1590 | mconfig->mcps = dfw_config->max_mcps; |
@@ -1579,10 +1614,6 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, | |||
1579 | mconfig->time_slot = dfw_config->time_slot; | 1614 | mconfig->time_slot = dfw_config->time_slot; |
1580 | mconfig->formats_config.caps_size = dfw_config->caps.caps_size; | 1615 | mconfig->formats_config.caps_size = dfw_config->caps.caps_size; |
1581 | 1616 | ||
1582 | if (dfw_config->is_loadable) | ||
1583 | memcpy(mconfig->guid, dfw_config->uuid, | ||
1584 | ARRAY_SIZE(dfw_config->uuid)); | ||
1585 | |||
1586 | mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * | 1617 | mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * |
1587 | sizeof(*mconfig->m_in_pin), | 1618 | sizeof(*mconfig->m_in_pin), |
1588 | GFP_KERNEL); | 1619 | GFP_KERNEL); |
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index de3c401284d9..e4b399cd7868 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h | |||
@@ -274,14 +274,14 @@ struct skl_pipe { | |||
274 | 274 | ||
275 | enum skl_module_state { | 275 | enum skl_module_state { |
276 | SKL_MODULE_UNINIT = 0, | 276 | SKL_MODULE_UNINIT = 0, |
277 | SKL_MODULE_INIT_DONE = 1, | 277 | SKL_MODULE_LOADED = 1, |
278 | SKL_MODULE_LOADED = 2, | 278 | SKL_MODULE_INIT_DONE = 2, |
279 | SKL_MODULE_UNLOADED = 3, | 279 | SKL_MODULE_BIND_DONE = 3, |
280 | SKL_MODULE_BIND_DONE = 4 | 280 | SKL_MODULE_UNLOADED = 4, |
281 | }; | 281 | }; |
282 | 282 | ||
283 | struct skl_module_cfg { | 283 | struct skl_module_cfg { |
284 | char guid[SKL_UUID_STR_SZ]; | 284 | u8 guid[16]; |
285 | struct skl_module_inst_id id; | 285 | struct skl_module_inst_id id; |
286 | u8 domain; | 286 | u8 domain; |
287 | bool homogenous_inputs; | 287 | bool homogenous_inputs; |
diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 1db88a63ac17..a32e5e9cc530 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h | |||
@@ -181,7 +181,7 @@ struct skl_dfw_pipe { | |||
181 | } __packed; | 181 | } __packed; |
182 | 182 | ||
183 | struct skl_dfw_module { | 183 | struct skl_dfw_module { |
184 | char uuid[SKL_UUID_STR_SZ]; | 184 | u8 uuid[16]; |
185 | 185 | ||
186 | u16 module_id; | 186 | u16 module_id; |
187 | u16 instance_id; | 187 | u16 instance_id; |
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ab5e25aaeee3..06d8c263c68f 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c | |||
@@ -222,20 +222,36 @@ static int skl_suspend(struct device *dev) | |||
222 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); | 222 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); |
223 | struct skl *skl = ebus_to_skl(ebus); | 223 | struct skl *skl = ebus_to_skl(ebus); |
224 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 224 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
225 | int ret = 0; | ||
225 | 226 | ||
226 | /* | 227 | /* |
227 | * Do not suspend if streams which are marked ignore suspend are | 228 | * Do not suspend if streams which are marked ignore suspend are |
228 | * running, we need to save the state for these and continue | 229 | * running, we need to save the state for these and continue |
229 | */ | 230 | */ |
230 | if (skl->supend_active) { | 231 | if (skl->supend_active) { |
232 | /* turn off the links and stop the CORB/RIRB DMA if it is On */ | ||
231 | snd_hdac_ext_bus_link_power_down_all(ebus); | 233 | snd_hdac_ext_bus_link_power_down_all(ebus); |
234 | |||
235 | if (ebus->cmd_dma_state) | ||
236 | snd_hdac_bus_stop_cmd_io(&ebus->bus); | ||
237 | |||
232 | enable_irq_wake(bus->irq); | 238 | enable_irq_wake(bus->irq); |
233 | pci_save_state(pci); | 239 | pci_save_state(pci); |
234 | pci_disable_device(pci); | 240 | pci_disable_device(pci); |
235 | return 0; | ||
236 | } else { | 241 | } else { |
237 | return _skl_suspend(ebus); | 242 | ret = _skl_suspend(ebus); |
243 | if (ret < 0) | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { | ||
248 | ret = snd_hdac_display_power(bus, false); | ||
249 | if (ret < 0) | ||
250 | dev_err(bus->dev, | ||
251 | "Cannot turn OFF display power on i915\n"); | ||
238 | } | 252 | } |
253 | |||
254 | return ret; | ||
239 | } | 255 | } |
240 | 256 | ||
241 | static int skl_resume(struct device *dev) | 257 | static int skl_resume(struct device *dev) |
@@ -244,6 +260,7 @@ static int skl_resume(struct device *dev) | |||
244 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); | 260 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); |
245 | struct skl *skl = ebus_to_skl(ebus); | 261 | struct skl *skl = ebus_to_skl(ebus); |
246 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 262 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
263 | struct hdac_ext_link *hlink = NULL; | ||
247 | int ret; | 264 | int ret; |
248 | 265 | ||
249 | /* Turned OFF in HDMI codec driver after codec reconfiguration */ | 266 | /* Turned OFF in HDMI codec driver after codec reconfiguration */ |
@@ -265,8 +282,29 @@ static int skl_resume(struct device *dev) | |||
265 | ret = pci_enable_device(pci); | 282 | ret = pci_enable_device(pci); |
266 | snd_hdac_ext_bus_link_power_up_all(ebus); | 283 | snd_hdac_ext_bus_link_power_up_all(ebus); |
267 | disable_irq_wake(bus->irq); | 284 | disable_irq_wake(bus->irq); |
285 | /* | ||
286 | * turn On the links which are On before active suspend | ||
287 | * and start the CORB/RIRB DMA if On before | ||
288 | * active suspend. | ||
289 | */ | ||
290 | list_for_each_entry(hlink, &ebus->hlink_list, list) { | ||
291 | if (hlink->ref_count) | ||
292 | snd_hdac_ext_bus_link_power_up(hlink); | ||
293 | } | ||
294 | |||
295 | if (ebus->cmd_dma_state) | ||
296 | snd_hdac_bus_init_cmd_io(&ebus->bus); | ||
268 | } else { | 297 | } else { |
269 | ret = _skl_resume(ebus); | 298 | ret = _skl_resume(ebus); |
299 | |||
300 | /* turn off the links which are off before suspend */ | ||
301 | list_for_each_entry(hlink, &ebus->hlink_list, list) { | ||
302 | if (!hlink->ref_count) | ||
303 | snd_hdac_ext_bus_link_power_down(hlink); | ||
304 | } | ||
305 | |||
306 | if (!ebus->cmd_dma_state) | ||
307 | snd_hdac_bus_stop_cmd_io(&ebus->bus); | ||
270 | } | 308 | } |
271 | 309 | ||
272 | return ret; | 310 | return ret; |
@@ -316,17 +354,20 @@ static int skl_free(struct hdac_ext_bus *ebus) | |||
316 | 354 | ||
317 | if (bus->irq >= 0) | 355 | if (bus->irq >= 0) |
318 | free_irq(bus->irq, (void *)bus); | 356 | free_irq(bus->irq, (void *)bus); |
319 | if (bus->remap_addr) | ||
320 | iounmap(bus->remap_addr); | ||
321 | |||
322 | snd_hdac_bus_free_stream_pages(bus); | 357 | snd_hdac_bus_free_stream_pages(bus); |
323 | snd_hdac_stream_free_all(ebus); | 358 | snd_hdac_stream_free_all(ebus); |
324 | snd_hdac_link_free_all(ebus); | 359 | snd_hdac_link_free_all(ebus); |
360 | |||
361 | if (bus->remap_addr) | ||
362 | iounmap(bus->remap_addr); | ||
363 | |||
325 | pci_release_regions(skl->pci); | 364 | pci_release_regions(skl->pci); |
326 | pci_disable_device(skl->pci); | 365 | pci_disable_device(skl->pci); |
327 | 366 | ||
328 | snd_hdac_ext_bus_exit(ebus); | 367 | snd_hdac_ext_bus_exit(ebus); |
329 | 368 | ||
369 | if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) | ||
370 | snd_hdac_i915_exit(&ebus->bus); | ||
330 | return 0; | 371 | return 0; |
331 | } | 372 | } |
332 | 373 | ||
@@ -599,6 +640,7 @@ static int skl_probe(struct pci_dev *pci, | |||
599 | struct skl *skl; | 640 | struct skl *skl; |
600 | struct hdac_ext_bus *ebus = NULL; | 641 | struct hdac_ext_bus *ebus = NULL; |
601 | struct hdac_bus *bus = NULL; | 642 | struct hdac_bus *bus = NULL; |
643 | struct hdac_ext_link *hlink = NULL; | ||
602 | int err; | 644 | int err; |
603 | 645 | ||
604 | /* we use ext core ops, so provide NULL for ops here */ | 646 | /* we use ext core ops, so provide NULL for ops here */ |
@@ -629,7 +671,7 @@ static int skl_probe(struct pci_dev *pci, | |||
629 | err = skl_machine_device_register(skl, | 671 | err = skl_machine_device_register(skl, |
630 | (void *)pci_id->driver_data); | 672 | (void *)pci_id->driver_data); |
631 | if (err < 0) | 673 | if (err < 0) |
632 | goto out_free; | 674 | goto out_nhlt_free; |
633 | 675 | ||
634 | err = skl_init_dsp(skl); | 676 | err = skl_init_dsp(skl); |
635 | if (err < 0) { | 677 | if (err < 0) { |
@@ -665,6 +707,12 @@ static int skl_probe(struct pci_dev *pci, | |||
665 | } | 707 | } |
666 | } | 708 | } |
667 | 709 | ||
710 | /* | ||
711 | * we are done probling so decrement link counts | ||
712 | */ | ||
713 | list_for_each_entry(hlink, &ebus->hlink_list, list) | ||
714 | snd_hdac_ext_bus_link_put(ebus, hlink); | ||
715 | |||
668 | /*configure PM */ | 716 | /*configure PM */ |
669 | pm_runtime_put_noidle(bus->dev); | 717 | pm_runtime_put_noidle(bus->dev); |
670 | pm_runtime_allow(bus->dev); | 718 | pm_runtime_allow(bus->dev); |
@@ -679,6 +727,8 @@ out_dsp_free: | |||
679 | skl_free_dsp(skl); | 727 | skl_free_dsp(skl); |
680 | out_mach_free: | 728 | out_mach_free: |
681 | skl_machine_device_unregister(skl); | 729 | skl_machine_device_unregister(skl); |
730 | out_nhlt_free: | ||
731 | skl_nhlt_free(skl->nhlt); | ||
682 | out_free: | 732 | out_free: |
683 | skl->init_failed = 1; | 733 | skl->init_failed = 1; |
684 | skl_free(ebus); | 734 | skl_free(ebus); |
@@ -719,16 +769,17 @@ static void skl_remove(struct pci_dev *pci) | |||
719 | if (skl->tplg) | 769 | if (skl->tplg) |
720 | release_firmware(skl->tplg); | 770 | release_firmware(skl->tplg); |
721 | 771 | ||
722 | if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) | ||
723 | snd_hdac_i915_exit(&ebus->bus); | ||
724 | |||
725 | if (pci_dev_run_wake(pci)) | 772 | if (pci_dev_run_wake(pci)) |
726 | pm_runtime_get_noresume(&pci->dev); | 773 | pm_runtime_get_noresume(&pci->dev); |
727 | pci_dev_put(pci); | 774 | |
775 | /* codec removal, invoke bus_device_remove */ | ||
776 | snd_hdac_ext_bus_device_remove(ebus); | ||
777 | |||
728 | skl_platform_unregister(&pci->dev); | 778 | skl_platform_unregister(&pci->dev); |
729 | skl_free_dsp(skl); | 779 | skl_free_dsp(skl); |
730 | skl_machine_device_unregister(skl); | 780 | skl_machine_device_unregister(skl); |
731 | skl_dmic_device_unregister(skl); | 781 | skl_dmic_device_unregister(skl); |
782 | skl_nhlt_free(skl->nhlt); | ||
732 | skl_free(ebus); | 783 | skl_free(ebus); |
733 | dev_set_drvdata(&pci->dev, NULL); | 784 | dev_set_drvdata(&pci->dev, NULL); |
734 | } | 785 | } |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 39e16fa7a92b..4b4b3876aea9 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h | |||
@@ -66,7 +66,7 @@ struct skl { | |||
66 | struct platform_device *dmic_dev; | 66 | struct platform_device *dmic_dev; |
67 | struct platform_device *i2s_dev; | 67 | struct platform_device *i2s_dev; |
68 | 68 | ||
69 | void *nhlt; /* nhlt ptr */ | 69 | struct nhlt_acpi_table *nhlt; /* nhlt ptr */ |
70 | struct skl_sst *skl_sst; /* sst skl ctx */ | 70 | struct skl_sst *skl_sst; /* sst skl ctx */ |
71 | 71 | ||
72 | struct skl_dsp_resource resource; | 72 | struct skl_dsp_resource resource; |
@@ -103,8 +103,8 @@ struct skl_dsp_ops { | |||
103 | int skl_platform_unregister(struct device *dev); | 103 | int skl_platform_unregister(struct device *dev); |
104 | int skl_platform_register(struct device *dev); | 104 | int skl_platform_register(struct device *dev); |
105 | 105 | ||
106 | void *skl_nhlt_init(struct device *dev); | 106 | struct nhlt_acpi_table *skl_nhlt_init(struct device *dev); |
107 | void skl_nhlt_free(void *addr); | 107 | void skl_nhlt_free(struct nhlt_acpi_table *addr); |
108 | struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, | 108 | struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, |
109 | u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); | 109 | u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); |
110 | 110 | ||
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index 132bb83f8e99..bc3c7b5ac752 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SND_KIRKWOOD_SOC | 1 | config SND_KIRKWOOD_SOC |
2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" | 2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" |
3 | depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST | 3 | depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST |
4 | depends on HAS_DMA | ||
4 | help | 5 | help |
5 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
6 | the Kirkwood I2S interface. You will also need to select the | 7 | the Kirkwood I2S interface. You will also need to select the |
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index f7e789e97fbc..3abf51c07851 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig | |||
@@ -43,6 +43,7 @@ config SND_SOC_MT8173_RT5650_RT5676 | |||
43 | depends on SND_SOC_MEDIATEK && I2C | 43 | depends on SND_SOC_MEDIATEK && I2C |
44 | select SND_SOC_RT5645 | 44 | select SND_SOC_RT5645 |
45 | select SND_SOC_RT5677 | 45 | select SND_SOC_RT5677 |
46 | select SND_SOC_HDMI_CODEC | ||
46 | help | 47 | help |
47 | This adds ASoC driver for Mediatek MT8173 boards | 48 | This adds ASoC driver for Mediatek MT8173 boards |
48 | with the RT5650 and RT5676 codecs. | 49 | with the RT5650 and RT5676 codecs. |
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 5c4c58c69c51..bb593926c62d 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c | |||
@@ -134,7 +134,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = { | |||
134 | enum { | 134 | enum { |
135 | DAI_LINK_PLAYBACK, | 135 | DAI_LINK_PLAYBACK, |
136 | DAI_LINK_CAPTURE, | 136 | DAI_LINK_CAPTURE, |
137 | DAI_LINK_HDMI, | ||
137 | DAI_LINK_CODEC_I2S, | 138 | DAI_LINK_CODEC_I2S, |
139 | DAI_LINK_HDMI_I2S, | ||
138 | DAI_LINK_INTERCODEC | 140 | DAI_LINK_INTERCODEC |
139 | }; | 141 | }; |
140 | 142 | ||
@@ -161,6 +163,16 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { | |||
161 | .dynamic = 1, | 163 | .dynamic = 1, |
162 | .dpcm_capture = 1, | 164 | .dpcm_capture = 1, |
163 | }, | 165 | }, |
166 | [DAI_LINK_HDMI] = { | ||
167 | .name = "HDMI", | ||
168 | .stream_name = "HDMI PCM", | ||
169 | .cpu_dai_name = "HDMI", | ||
170 | .codec_name = "snd-soc-dummy", | ||
171 | .codec_dai_name = "snd-soc-dummy-dai", | ||
172 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
173 | .dynamic = 1, | ||
174 | .dpcm_playback = 1, | ||
175 | }, | ||
164 | 176 | ||
165 | /* Back End DAI links */ | 177 | /* Back End DAI links */ |
166 | [DAI_LINK_CODEC_I2S] = { | 178 | [DAI_LINK_CODEC_I2S] = { |
@@ -177,6 +189,13 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { | |||
177 | .dpcm_playback = 1, | 189 | .dpcm_playback = 1, |
178 | .dpcm_capture = 1, | 190 | .dpcm_capture = 1, |
179 | }, | 191 | }, |
192 | [DAI_LINK_HDMI_I2S] = { | ||
193 | .name = "HDMI BE", | ||
194 | .cpu_dai_name = "HDMIO", | ||
195 | .no_pcm = 1, | ||
196 | .codec_dai_name = "i2s-hifi", | ||
197 | .dpcm_playback = 1, | ||
198 | }, | ||
180 | /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ | 199 | /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ |
181 | [DAI_LINK_INTERCODEC] = { | 200 | [DAI_LINK_INTERCODEC] = { |
182 | .name = "rt5650_rt5676 intercodec", | 201 | .name = "rt5650_rt5676 intercodec", |
@@ -251,6 +270,14 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) | |||
251 | mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node = | 270 | mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node = |
252 | mt8173_rt5650_rt5676_codecs[1].of_node; | 271 | mt8173_rt5650_rt5676_codecs[1].of_node; |
253 | 272 | ||
273 | mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codec_of_node = | ||
274 | of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2); | ||
275 | if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codec_of_node) { | ||
276 | dev_err(&pdev->dev, | ||
277 | "Property 'audio-codec' missing or invalid\n"); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
254 | card->dev = &pdev->dev; | 281 | card->dev = &pdev->dev; |
255 | platform_set_drvdata(pdev, card); | 282 | platform_set_drvdata(pdev, card); |
256 | 283 | ||
diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173-rt5650.c index bb09bb1b7f1c..a27a6673dbe3 100644 --- a/sound/soc/mediatek/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173-rt5650.c | |||
@@ -85,12 +85,29 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) | |||
85 | { | 85 | { |
86 | struct snd_soc_card *card = runtime->card; | 86 | struct snd_soc_card *card = runtime->card; |
87 | struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; | 87 | struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; |
88 | const char *codec_capture_dai = runtime->codec_dais[1]->name; | ||
88 | int ret; | 89 | int ret; |
89 | 90 | ||
90 | rt5645_sel_asrc_clk_src(codec, | 91 | rt5645_sel_asrc_clk_src(codec, |
91 | RT5645_DA_STEREO_FILTER | | 92 | RT5645_DA_STEREO_FILTER, |
92 | RT5645_AD_STEREO_FILTER, | ||
93 | RT5645_CLK_SEL_I2S1_ASRC); | 93 | RT5645_CLK_SEL_I2S1_ASRC); |
94 | |||
95 | if (!strcmp(codec_capture_dai, "rt5645-aif1")) { | ||
96 | rt5645_sel_asrc_clk_src(codec, | ||
97 | RT5645_AD_STEREO_FILTER, | ||
98 | RT5645_CLK_SEL_I2S1_ASRC); | ||
99 | } else if (!strcmp(codec_capture_dai, "rt5645-aif2")) { | ||
100 | rt5645_sel_asrc_clk_src(codec, | ||
101 | RT5645_AD_STEREO_FILTER, | ||
102 | RT5645_CLK_SEL_I2S2_ASRC); | ||
103 | } else { | ||
104 | dev_warn(card->dev, | ||
105 | "Only one dai codec found in DTS, enabled rt5645 AD filter\n"); | ||
106 | rt5645_sel_asrc_clk_src(codec, | ||
107 | RT5645_AD_STEREO_FILTER, | ||
108 | RT5645_CLK_SEL_I2S1_ASRC); | ||
109 | } | ||
110 | |||
94 | /* enable jack detection */ | 111 | /* enable jack detection */ |
95 | ret = snd_soc_card_jack_new(card, "Headset Jack", | 112 | ret = snd_soc_card_jack_new(card, "Headset Jack", |
96 | SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | | 113 | SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | |
@@ -110,6 +127,11 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) | |||
110 | 127 | ||
111 | static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { | 128 | static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { |
112 | { | 129 | { |
130 | /* Playback */ | ||
131 | .dai_name = "rt5645-aif1", | ||
132 | }, | ||
133 | { | ||
134 | /* Capture */ | ||
113 | .dai_name = "rt5645-aif1", | 135 | .dai_name = "rt5645-aif1", |
114 | }, | 136 | }, |
115 | }; | 137 | }; |
@@ -149,7 +171,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { | |||
149 | .cpu_dai_name = "I2S", | 171 | .cpu_dai_name = "I2S", |
150 | .no_pcm = 1, | 172 | .no_pcm = 1, |
151 | .codecs = mt8173_rt5650_codecs, | 173 | .codecs = mt8173_rt5650_codecs, |
152 | .num_codecs = 1, | 174 | .num_codecs = 2, |
153 | .init = mt8173_rt5650_init, | 175 | .init = mt8173_rt5650_init, |
154 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 176 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
155 | SND_SOC_DAIFMT_CBS_CFS, | 177 | SND_SOC_DAIFMT_CBS_CFS, |
@@ -177,6 +199,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) | |||
177 | { | 199 | { |
178 | struct snd_soc_card *card = &mt8173_rt5650_card; | 200 | struct snd_soc_card *card = &mt8173_rt5650_card; |
179 | struct device_node *platform_node; | 201 | struct device_node *platform_node; |
202 | struct device_node *np; | ||
203 | const char *codec_capture_dai; | ||
180 | int i, ret; | 204 | int i, ret; |
181 | 205 | ||
182 | platform_node = of_parse_phandle(pdev->dev.of_node, | 206 | platform_node = of_parse_phandle(pdev->dev.of_node, |
@@ -199,6 +223,26 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) | |||
199 | "Property 'audio-codec' missing or invalid\n"); | 223 | "Property 'audio-codec' missing or invalid\n"); |
200 | return -EINVAL; | 224 | return -EINVAL; |
201 | } | 225 | } |
226 | mt8173_rt5650_codecs[1].of_node = mt8173_rt5650_codecs[0].of_node; | ||
227 | |||
228 | if (of_find_node_by_name(platform_node, "codec-capture")) { | ||
229 | np = of_get_child_by_name(pdev->dev.of_node, "codec-capture"); | ||
230 | if (!np) { | ||
231 | dev_err(&pdev->dev, | ||
232 | "%s: Can't find codec-capture DT node\n", | ||
233 | __func__); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | ret = snd_soc_of_get_dai_name(np, &codec_capture_dai); | ||
237 | if (ret < 0) { | ||
238 | dev_err(&pdev->dev, | ||
239 | "%s codec_capture_dai name fail %d\n", | ||
240 | __func__, ret); | ||
241 | return ret; | ||
242 | } | ||
243 | mt8173_rt5650_codecs[1].dai_name = codec_capture_dai; | ||
244 | } | ||
245 | |||
202 | card->dev = &pdev->dev; | 246 | card->dev = &pdev->dev; |
203 | platform_set_drvdata(pdev, card); | 247 | platform_set_drvdata(pdev, card); |
204 | 248 | ||
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index f1c58a2c12fb..2b5df2ef51a3 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c | |||
@@ -123,6 +123,7 @@ | |||
123 | #define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8) | 123 | #define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8) |
124 | #define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4) | 124 | #define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4) |
125 | #define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3) | 125 | #define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3) |
126 | #define AFE_TDM_CON1_LRCK_INV (0x1 << 2) | ||
126 | #define AFE_TDM_CON1_BCK_INV (0x1 << 1) | 127 | #define AFE_TDM_CON1_BCK_INV (0x1 << 1) |
127 | #define AFE_TDM_CON1_EN (0x1 << 0) | 128 | #define AFE_TDM_CON1_EN (0x1 << 0) |
128 | 129 | ||
@@ -449,6 +450,7 @@ static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, | |||
449 | runtime->rate * runtime->channels * 32); | 450 | runtime->rate * runtime->channels * 32); |
450 | 451 | ||
451 | val = AFE_TDM_CON1_BCK_INV | | 452 | val = AFE_TDM_CON1_BCK_INV | |
453 | AFE_TDM_CON1_LRCK_INV | | ||
452 | AFE_TDM_CON1_1_BCK_DELAY | | 454 | AFE_TDM_CON1_1_BCK_DELAY | |
453 | AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */ | 455 | AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */ |
454 | AFE_TDM_CON1_WLEN_32BIT | | 456 | AFE_TDM_CON1_WLEN_32BIT | |
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index c7563e230c7d..4a16e778966b 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c | |||
@@ -260,6 +260,10 @@ static void omap_st_on(struct omap_mcbsp *mcbsp) | |||
260 | if (mcbsp->pdata->enable_st_clock) | 260 | if (mcbsp->pdata->enable_st_clock) |
261 | mcbsp->pdata->enable_st_clock(mcbsp->id, 1); | 261 | mcbsp->pdata->enable_st_clock(mcbsp->id, 1); |
262 | 262 | ||
263 | /* Disable Sidetone clock auto-gating for normal operation */ | ||
264 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
265 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); | ||
266 | |||
263 | /* Enable McBSP Sidetone */ | 267 | /* Enable McBSP Sidetone */ |
264 | w = MCBSP_READ(mcbsp, SSELCR); | 268 | w = MCBSP_READ(mcbsp, SSELCR); |
265 | MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); | 269 | MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); |
@@ -279,6 +283,10 @@ static void omap_st_off(struct omap_mcbsp *mcbsp) | |||
279 | w = MCBSP_READ(mcbsp, SSELCR); | 283 | w = MCBSP_READ(mcbsp, SSELCR); |
280 | MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); | 284 | MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); |
281 | 285 | ||
286 | /* Enable Sidetone clock auto-gating to reduce power consumption */ | ||
287 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
288 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE); | ||
289 | |||
282 | if (mcbsp->pdata->enable_st_clock) | 290 | if (mcbsp->pdata->enable_st_clock) |
283 | mcbsp->pdata->enable_st_clock(mcbsp->id, 0); | 291 | mcbsp->pdata->enable_st_clock(mcbsp->id, 0); |
284 | } | 292 | } |
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 99381a27295b..a84f677234f0 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -82,6 +82,8 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, | |||
82 | struct dma_chan *chan; | 82 | struct dma_chan *chan; |
83 | int err = 0; | 83 | int err = 0; |
84 | 84 | ||
85 | memset(&config, 0x00, sizeof(config)); | ||
86 | |||
85 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | 87 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
86 | 88 | ||
87 | /* return if this is a bufferless transfer e.g. | 89 | /* return if this is a bufferless transfer e.g. |
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index ec522e94b0e2..b6cb9950f05d 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c | |||
@@ -133,3 +133,4 @@ module_platform_driver(mmp_driver); | |||
133 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | 133 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); |
134 | MODULE_DESCRIPTION("ALSA SoC Brownstone"); | 134 | MODULE_DESCRIPTION("ALSA SoC Brownstone"); |
135 | MODULE_LICENSE("GPL"); | 135 | MODULE_LICENSE("GPL"); |
136 | MODULE_ALIAS("platform:brownstone-audio"); | ||
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 5c8f9db50a47..d1661fa6ee08 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -207,3 +207,4 @@ module_platform_driver(mioa701_wm9713_driver); | |||
207 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); | 207 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); |
208 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); | 208 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); |
209 | MODULE_LICENSE("GPL"); | 209 | MODULE_LICENSE("GPL"); |
210 | MODULE_ALIAS("platform:mioa701-wm9713"); | ||
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 51e790d006f5..96df9b2d8fc4 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c | |||
@@ -248,3 +248,4 @@ module_platform_driver(mmp_pcm_driver); | |||
248 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | 248 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); |
249 | MODULE_DESCRIPTION("MMP Soc Audio DMA module"); | 249 | MODULE_DESCRIPTION("MMP Soc Audio DMA module"); |
250 | MODULE_LICENSE("GPL"); | 250 | MODULE_LICENSE("GPL"); |
251 | MODULE_ALIAS("platform:mmp-pcm-audio"); | ||
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index eca60c29791a..ca8b23f8c525 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c | |||
@@ -482,3 +482,4 @@ module_platform_driver(asoc_mmp_sspa_driver); | |||
482 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | 482 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); |
483 | MODULE_DESCRIPTION("MMP SSPA SoC Interface"); | 483 | MODULE_DESCRIPTION("MMP SSPA SoC Interface"); |
484 | MODULE_LICENSE("GPL"); | 484 | MODULE_LICENSE("GPL"); |
485 | MODULE_ALIAS("platform:mmp-sspa-dai"); | ||
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 4e74d9573f03..bcc81e920a67 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c | |||
@@ -161,3 +161,4 @@ module_platform_driver(palm27x_wm9712_driver); | |||
161 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | 161 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); |
162 | MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); | 162 | MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); |
163 | MODULE_LICENSE("GPL"); | 163 | MODULE_LICENSE("GPL"); |
164 | MODULE_ALIAS("platform:palm27x-asoc"); | ||
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index da03fad1b9cd..3cad990dad2c 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -833,3 +833,4 @@ module_platform_driver(asoc_ssp_driver); | |||
833 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 833 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
834 | MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); | 834 | MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); |
835 | MODULE_LICENSE("GPL"); | 835 | MODULE_LICENSE("GPL"); |
836 | MODULE_ALIAS("platform:pxa-ssp-dai"); | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index f3de615aacd7..9615e6de1306 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -287,3 +287,4 @@ module_platform_driver(pxa2xx_ac97_driver); | |||
287 | MODULE_AUTHOR("Nicolas Pitre"); | 287 | MODULE_AUTHOR("Nicolas Pitre"); |
288 | MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); | 288 | MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); |
289 | MODULE_LICENSE("GPL"); | 289 | MODULE_LICENSE("GPL"); |
290 | MODULE_ALIAS("platform:pxa2xx-ac97"); | ||
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 9f390398d518..410d48b93031 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -117,3 +117,4 @@ module_platform_driver(pxa_pcm_driver); | |||
117 | MODULE_AUTHOR("Nicolas Pitre"); | 117 | MODULE_AUTHOR("Nicolas Pitre"); |
118 | MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); | 118 | MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); |
119 | MODULE_LICENSE("GPL"); | 119 | MODULE_LICENSE("GPL"); |
120 | MODULE_ALIAS("platform:pxa-pcm-audio"); | ||
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 6e8665430bd5..db000c6987a1 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c | |||
@@ -474,7 +474,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
474 | struct lpass_data *drvdata = | 474 | struct lpass_data *drvdata = |
475 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 475 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
476 | struct lpass_variant *v = drvdata->variant; | 476 | struct lpass_variant *v = drvdata->variant; |
477 | int ret; | 477 | int ret = -EINVAL; |
478 | struct lpass_pcm_data *data; | 478 | struct lpass_pcm_data *data; |
479 | size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; | 479 | size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; |
480 | 480 | ||
@@ -491,7 +491,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
491 | data->rdma_ch = v->alloc_dma_channel(drvdata, | 491 | data->rdma_ch = v->alloc_dma_channel(drvdata, |
492 | SNDRV_PCM_STREAM_PLAYBACK); | 492 | SNDRV_PCM_STREAM_PLAYBACK); |
493 | 493 | ||
494 | if (IS_ERR_VALUE(data->rdma_ch)) | 494 | if (data->rdma_ch < 0) |
495 | return data->rdma_ch; | 495 | return data->rdma_ch; |
496 | 496 | ||
497 | drvdata->substream[data->rdma_ch] = psubstream; | 497 | drvdata->substream[data->rdma_ch] = psubstream; |
@@ -518,8 +518,10 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
518 | data->wrdma_ch = v->alloc_dma_channel(drvdata, | 518 | data->wrdma_ch = v->alloc_dma_channel(drvdata, |
519 | SNDRV_PCM_STREAM_CAPTURE); | 519 | SNDRV_PCM_STREAM_CAPTURE); |
520 | 520 | ||
521 | if (IS_ERR_VALUE(data->wrdma_ch)) | 521 | if (data->wrdma_ch < 0) { |
522 | ret = data->wrdma_ch; | ||
522 | goto capture_alloc_err; | 523 | goto capture_alloc_err; |
524 | } | ||
523 | 525 | ||
524 | drvdata->substream[data->wrdma_ch] = csubstream; | 526 | drvdata->substream[data->wrdma_ch] = csubstream; |
525 | 527 | ||
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 2f8e20416bd3..574c6af28c06 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c | |||
@@ -34,6 +34,13 @@ struct rk_i2s_dev { | |||
34 | 34 | ||
35 | struct regmap *regmap; | 35 | struct regmap *regmap; |
36 | 36 | ||
37 | /* | ||
38 | * Used to indicate the tx/rx status. | ||
39 | * I2S controller hopes to start the tx and rx together, | ||
40 | * also to stop them when they are both try to stop. | ||
41 | */ | ||
42 | bool tx_start; | ||
43 | bool rx_start; | ||
37 | bool is_master_mode; | 44 | bool is_master_mode; |
38 | }; | 45 | }; |
39 | 46 | ||
@@ -75,29 +82,37 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) | |||
75 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); | 82 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); |
76 | 83 | ||
77 | regmap_update_bits(i2s->regmap, I2S_XFER, | 84 | regmap_update_bits(i2s->regmap, I2S_XFER, |
78 | I2S_XFER_TXS_START, | 85 | I2S_XFER_TXS_START | I2S_XFER_RXS_START, |
79 | I2S_XFER_TXS_START); | 86 | I2S_XFER_TXS_START | I2S_XFER_RXS_START); |
87 | |||
88 | i2s->tx_start = true; | ||
80 | } else { | 89 | } else { |
90 | i2s->tx_start = false; | ||
91 | |||
81 | regmap_update_bits(i2s->regmap, I2S_DMACR, | 92 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
82 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); | 93 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); |
83 | 94 | ||
84 | regmap_update_bits(i2s->regmap, I2S_XFER, | 95 | if (!i2s->rx_start) { |
85 | I2S_XFER_TXS_START, | 96 | regmap_update_bits(i2s->regmap, I2S_XFER, |
86 | I2S_XFER_TXS_STOP); | 97 | I2S_XFER_TXS_START | |
98 | I2S_XFER_RXS_START, | ||
99 | I2S_XFER_TXS_STOP | | ||
100 | I2S_XFER_RXS_STOP); | ||
87 | 101 | ||
88 | regmap_update_bits(i2s->regmap, I2S_CLR, | 102 | regmap_update_bits(i2s->regmap, I2S_CLR, |
89 | I2S_CLR_TXC, | 103 | I2S_CLR_TXC | I2S_CLR_RXC, |
90 | I2S_CLR_TXC); | 104 | I2S_CLR_TXC | I2S_CLR_RXC); |
91 | 105 | ||
92 | regmap_read(i2s->regmap, I2S_CLR, &val); | ||
93 | |||
94 | /* Should wait for clear operation to finish */ | ||
95 | while (val & I2S_CLR_TXC) { | ||
96 | regmap_read(i2s->regmap, I2S_CLR, &val); | 106 | regmap_read(i2s->regmap, I2S_CLR, &val); |
97 | retry--; | 107 | |
98 | if (!retry) { | 108 | /* Should wait for clear operation to finish */ |
99 | dev_warn(i2s->dev, "fail to clear\n"); | 109 | while (val) { |
100 | break; | 110 | regmap_read(i2s->regmap, I2S_CLR, &val); |
111 | retry--; | ||
112 | if (!retry) { | ||
113 | dev_warn(i2s->dev, "fail to clear\n"); | ||
114 | break; | ||
115 | } | ||
101 | } | 116 | } |
102 | } | 117 | } |
103 | } | 118 | } |
@@ -113,29 +128,37 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) | |||
113 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); | 128 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); |
114 | 129 | ||
115 | regmap_update_bits(i2s->regmap, I2S_XFER, | 130 | regmap_update_bits(i2s->regmap, I2S_XFER, |
116 | I2S_XFER_RXS_START, | 131 | I2S_XFER_TXS_START | I2S_XFER_RXS_START, |
117 | I2S_XFER_RXS_START); | 132 | I2S_XFER_TXS_START | I2S_XFER_RXS_START); |
133 | |||
134 | i2s->rx_start = true; | ||
118 | } else { | 135 | } else { |
136 | i2s->rx_start = false; | ||
137 | |||
119 | regmap_update_bits(i2s->regmap, I2S_DMACR, | 138 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
120 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); | 139 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); |
121 | 140 | ||
122 | regmap_update_bits(i2s->regmap, I2S_XFER, | 141 | if (!i2s->tx_start) { |
123 | I2S_XFER_RXS_START, | 142 | regmap_update_bits(i2s->regmap, I2S_XFER, |
124 | I2S_XFER_RXS_STOP); | 143 | I2S_XFER_TXS_START | |
144 | I2S_XFER_RXS_START, | ||
145 | I2S_XFER_TXS_STOP | | ||
146 | I2S_XFER_RXS_STOP); | ||
125 | 147 | ||
126 | regmap_update_bits(i2s->regmap, I2S_CLR, | 148 | regmap_update_bits(i2s->regmap, I2S_CLR, |
127 | I2S_CLR_RXC, | 149 | I2S_CLR_TXC | I2S_CLR_RXC, |
128 | I2S_CLR_RXC); | 150 | I2S_CLR_TXC | I2S_CLR_RXC); |
129 | 151 | ||
130 | regmap_read(i2s->regmap, I2S_CLR, &val); | ||
131 | |||
132 | /* Should wait for clear operation to finish */ | ||
133 | while (val & I2S_CLR_RXC) { | ||
134 | regmap_read(i2s->regmap, I2S_CLR, &val); | 152 | regmap_read(i2s->regmap, I2S_CLR, &val); |
135 | retry--; | 153 | |
136 | if (!retry) { | 154 | /* Should wait for clear operation to finish */ |
137 | dev_warn(i2s->dev, "fail to clear\n"); | 155 | while (val) { |
138 | break; | 156 | regmap_read(i2s->regmap, I2S_CLR, &val); |
157 | retry--; | ||
158 | if (!retry) { | ||
159 | dev_warn(i2s->dev, "fail to clear\n"); | ||
160 | break; | ||
161 | } | ||
139 | } | 162 | } |
140 | } | 163 | } |
141 | } | 164 | } |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 606399de684d..49354d17ea55 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -492,9 +492,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
492 | */ | 492 | */ |
493 | if (!count) { | 493 | if (!count) { |
494 | clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], | 494 | clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], |
495 | parent_clk_name, | 495 | parent_clk_name, 0, req_rate); |
496 | (parent_clk_name) ? | ||
497 | 0 : CLK_IS_ROOT, req_rate); | ||
498 | if (!IS_ERR(clk)) { | 496 | if (!IS_ERR(clk)) { |
499 | adg->clkout[CLKOUT] = clk; | 497 | adg->clkout[CLKOUT] = clk; |
500 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | 498 | of_clk_add_provider(np, of_clk_src_simple_get, clk); |
@@ -506,9 +504,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
506 | else { | 504 | else { |
507 | for (i = 0; i < CLKOUTMAX; i++) { | 505 | for (i = 0; i < CLKOUTMAX; i++) { |
508 | clk = clk_register_fixed_rate(dev, clkout_name[i], | 506 | clk = clk_register_fixed_rate(dev, clkout_name[i], |
509 | parent_clk_name, | 507 | parent_clk_name, 0, |
510 | (parent_clk_name) ? | ||
511 | 0 : CLK_IS_ROOT, | ||
512 | req_rate); | 508 | req_rate); |
513 | if (!IS_ERR(clk)) { | 509 | if (!IS_ERR(clk)) { |
514 | adg->onecell.clks = adg->clkout; | 510 | adg->onecell.clks = adg->clkout; |
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 7658e8fd7bdc..6bc93cbb3049 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
@@ -316,11 +316,15 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, | |||
316 | size = ARRAY_SIZE(gen2_id_table_cmd); | 316 | size = ARRAY_SIZE(gen2_id_table_cmd); |
317 | } | 317 | } |
318 | 318 | ||
319 | if (!entry) | 319 | if ((!entry) || (size <= id)) { |
320 | return 0xFF; | 320 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); |
321 | 321 | ||
322 | if (size <= id) | 322 | dev_err(dev, "unknown connection (%s[%d])\n", |
323 | return 0xFF; | 323 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
324 | |||
325 | /* use non-prohibited SRS number as error */ | ||
326 | return 0x00; /* SSI00 */ | ||
327 | } | ||
324 | 328 | ||
325 | return entry[id]; | 329 | return entry[id]; |
326 | } | 330 | } |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index fc89a67258ca..a8f61d79333b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -276,8 +276,9 @@ struct rsnd_mod { | |||
276 | /* | 276 | /* |
277 | * status | 277 | * status |
278 | * | 278 | * |
279 | * 0xH0000CB0 | 279 | * 0xH0000CBA |
280 | * | 280 | * |
281 | * A 0: probe 1: remove | ||
281 | * B 0: init 1: quit | 282 | * B 0: init 1: quit |
282 | * C 0: start 1: stop | 283 | * C 0: start 1: stop |
283 | * | 284 | * |
@@ -287,19 +288,19 @@ struct rsnd_mod { | |||
287 | * H 0: fallback | 288 | * H 0: fallback |
288 | * H 0: hw_params | 289 | * H 0: hw_params |
289 | */ | 290 | */ |
291 | #define __rsnd_mod_shift_probe 0 | ||
292 | #define __rsnd_mod_shift_remove 0 | ||
290 | #define __rsnd_mod_shift_init 4 | 293 | #define __rsnd_mod_shift_init 4 |
291 | #define __rsnd_mod_shift_quit 4 | 294 | #define __rsnd_mod_shift_quit 4 |
292 | #define __rsnd_mod_shift_start 8 | 295 | #define __rsnd_mod_shift_start 8 |
293 | #define __rsnd_mod_shift_stop 8 | 296 | #define __rsnd_mod_shift_stop 8 |
294 | #define __rsnd_mod_shift_probe 28 /* always called */ | ||
295 | #define __rsnd_mod_shift_remove 28 /* always called */ | ||
296 | #define __rsnd_mod_shift_irq 28 /* always called */ | 297 | #define __rsnd_mod_shift_irq 28 /* always called */ |
297 | #define __rsnd_mod_shift_pcm_new 28 /* always called */ | 298 | #define __rsnd_mod_shift_pcm_new 28 /* always called */ |
298 | #define __rsnd_mod_shift_fallback 28 /* always called */ | 299 | #define __rsnd_mod_shift_fallback 28 /* always called */ |
299 | #define __rsnd_mod_shift_hw_params 28 /* always called */ | 300 | #define __rsnd_mod_shift_hw_params 28 /* always called */ |
300 | 301 | ||
301 | #define __rsnd_mod_add_probe 0 | 302 | #define __rsnd_mod_add_probe 1 |
302 | #define __rsnd_mod_add_remove 0 | 303 | #define __rsnd_mod_add_remove -1 |
303 | #define __rsnd_mod_add_init 1 | 304 | #define __rsnd_mod_add_init 1 |
304 | #define __rsnd_mod_add_quit -1 | 305 | #define __rsnd_mod_add_quit -1 |
305 | #define __rsnd_mod_add_start 1 | 306 | #define __rsnd_mod_add_start 1 |
@@ -310,7 +311,7 @@ struct rsnd_mod { | |||
310 | #define __rsnd_mod_add_hw_params 0 | 311 | #define __rsnd_mod_add_hw_params 0 |
311 | 312 | ||
312 | #define __rsnd_mod_call_probe 0 | 313 | #define __rsnd_mod_call_probe 0 |
313 | #define __rsnd_mod_call_remove 0 | 314 | #define __rsnd_mod_call_remove 1 |
314 | #define __rsnd_mod_call_init 0 | 315 | #define __rsnd_mod_call_init 0 |
315 | #define __rsnd_mod_call_quit 1 | 316 | #define __rsnd_mod_call_quit 1 |
316 | #define __rsnd_mod_call_start 0 | 317 | #define __rsnd_mod_call_start 0 |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 15d6ffe8be74..e39f916d0f2f 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -572,6 +572,9 @@ int rsnd_src_probe(struct rsnd_priv *priv) | |||
572 | 572 | ||
573 | i = 0; | 573 | i = 0; |
574 | for_each_child_of_node(node, np) { | 574 | for_each_child_of_node(node, np) { |
575 | if (!of_device_is_available(np)) | ||
576 | goto skip; | ||
577 | |||
575 | src = rsnd_src_get(priv, i); | 578 | src = rsnd_src_get(priv, i); |
576 | 579 | ||
577 | snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", | 580 | snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", |
@@ -595,6 +598,7 @@ int rsnd_src_probe(struct rsnd_priv *priv) | |||
595 | if (ret) | 598 | if (ret) |
596 | goto rsnd_src_probe_done; | 599 | goto rsnd_src_probe_done; |
597 | 600 | ||
601 | skip: | ||
598 | i++; | 602 | i++; |
599 | } | 603 | } |
600 | 604 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d2e62b159610..16369cad4803 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -930,7 +930,18 @@ static struct snd_soc_component *soc_find_component( | |||
930 | return NULL; | 930 | return NULL; |
931 | } | 931 | } |
932 | 932 | ||
933 | static struct snd_soc_dai *snd_soc_find_dai( | 933 | /** |
934 | * snd_soc_find_dai - Find a registered DAI | ||
935 | * | ||
936 | * @dlc: name of the DAI and optional component info to match | ||
937 | * | ||
938 | * This function will search all regsitered components and their DAIs to | ||
939 | * find the DAI of the same name. The component's of_node and name | ||
940 | * should also match if being specified. | ||
941 | * | ||
942 | * Return: pointer of DAI, or NULL if not found. | ||
943 | */ | ||
944 | struct snd_soc_dai *snd_soc_find_dai( | ||
934 | const struct snd_soc_dai_link_component *dlc) | 945 | const struct snd_soc_dai_link_component *dlc) |
935 | { | 946 | { |
936 | struct snd_soc_component *component; | 947 | struct snd_soc_component *component; |
@@ -959,6 +970,7 @@ static struct snd_soc_dai *snd_soc_find_dai( | |||
959 | 970 | ||
960 | return NULL; | 971 | return NULL; |
961 | } | 972 | } |
973 | EXPORT_SYMBOL_GPL(snd_soc_find_dai); | ||
962 | 974 | ||
963 | static bool soc_is_dai_link_bound(struct snd_soc_card *card, | 975 | static bool soc_is_dai_link_bound(struct snd_soc_card *card, |
964 | struct snd_soc_dai_link *dai_link) | 976 | struct snd_soc_dai_link *dai_link) |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 801ae1a81dfd..c4464858bf01 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -2188,6 +2188,13 @@ static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, | |||
2188 | int count = 0; | 2188 | int count = 0; |
2189 | char *state = "not set"; | 2189 | char *state = "not set"; |
2190 | 2190 | ||
2191 | /* card won't be set for the dummy component, as a spot fix | ||
2192 | * we're checking for that case specifically here but in future | ||
2193 | * we will ensure that the dummy component looks like others. | ||
2194 | */ | ||
2195 | if (!cmpnt->card) | ||
2196 | return 0; | ||
2197 | |||
2191 | list_for_each_entry(w, &cmpnt->card->widgets, list) { | 2198 | list_for_each_entry(w, &cmpnt->card->widgets, list) { |
2192 | if (w->dapm != dapm) | 2199 | if (w->dapm != dapm) |
2193 | continue; | 2200 | continue; |
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6fd1906af387..6cef3977507a 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c | |||
@@ -163,31 +163,42 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea | |||
163 | } | 163 | } |
164 | 164 | ||
165 | /* | 165 | /* |
166 | * Prepare formats mask for valid/allowed sample types. If the dma does | 166 | * If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep |
167 | * not have support for the given physical word size, it needs to be | 167 | * hw.formats set to 0, meaning no restrictions are in place. |
168 | * masked out so user space can not use the format which produces | 168 | * In this case it's the responsibility of the DAI driver to |
169 | * corrupted audio. | 169 | * provide the supported format information. |
170 | * In case the dma driver does not implement the slave_caps the default | ||
171 | * assumption is that it supports 1, 2 and 4 bytes widths. | ||
172 | */ | 170 | */ |
173 | for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { | 171 | if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK)) |
174 | int bits = snd_pcm_format_physical_width(i); | 172 | /* |
175 | 173 | * Prepare formats mask for valid/allowed sample types. If the | |
176 | /* Enable only samples with DMA supported physical widths */ | 174 | * dma does not have support for the given physical word size, |
177 | switch (bits) { | 175 | * it needs to be masked out so user space can not use the |
178 | case 8: | 176 | * format which produces corrupted audio. |
179 | case 16: | 177 | * In case the dma driver does not implement the slave_caps the |
180 | case 24: | 178 | * default assumption is that it supports 1, 2 and 4 bytes |
181 | case 32: | 179 | * widths. |
182 | case 64: | 180 | */ |
183 | if (addr_widths & (1 << (bits / 8))) | 181 | for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) { |
184 | hw.formats |= (1LL << i); | 182 | int bits = snd_pcm_format_physical_width(i); |
185 | break; | 183 | |
186 | default: | 184 | /* |
187 | /* Unsupported types */ | 185 | * Enable only samples with DMA supported physical |
188 | break; | 186 | * widths |
187 | */ | ||
188 | switch (bits) { | ||
189 | case 8: | ||
190 | case 16: | ||
191 | case 24: | ||
192 | case 32: | ||
193 | case 64: | ||
194 | if (addr_widths & (1 << (bits / 8))) | ||
195 | hw.formats |= (1LL << i); | ||
196 | break; | ||
197 | default: | ||
198 | /* Unsupported types */ | ||
199 | break; | ||
200 | } | ||
189 | } | 201 | } |
190 | } | ||
191 | 202 | ||
192 | return snd_soc_set_runtime_hwparams(substream, &hw); | 203 | return snd_soc_set_runtime_hwparams(substream, &hw); |
193 | } | 204 | } |
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 1cf94d7fb9f4..ee7f15aa46fc 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c | |||
@@ -1023,6 +1023,11 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, | |||
1023 | 1023 | ||
1024 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; | 1024 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; |
1025 | 1025 | ||
1026 | if (control_hdr->size != sizeof(*control_hdr)) { | ||
1027 | dev_err(tplg->dev, "ASoC: invalid control size\n"); | ||
1028 | return -EINVAL; | ||
1029 | } | ||
1030 | |||
1026 | switch (control_hdr->ops.info) { | 1031 | switch (control_hdr->ops.info) { |
1027 | case SND_SOC_TPLG_CTL_VOLSW: | 1032 | case SND_SOC_TPLG_CTL_VOLSW: |
1028 | case SND_SOC_TPLG_CTL_STROBE: | 1033 | case SND_SOC_TPLG_CTL_STROBE: |
@@ -1476,6 +1481,8 @@ widget: | |||
1476 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; | 1481 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; |
1477 | widget->dobj.ops = tplg->ops; | 1482 | widget->dobj.ops = tplg->ops; |
1478 | widget->dobj.index = tplg->index; | 1483 | widget->dobj.index = tplg->index; |
1484 | kfree(template.sname); | ||
1485 | kfree(template.name); | ||
1479 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); | 1486 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); |
1480 | return 0; | 1487 | return 0; |
1481 | 1488 | ||
@@ -1499,10 +1506,17 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, | |||
1499 | 1506 | ||
1500 | for (i = 0; i < count; i++) { | 1507 | for (i = 0; i < count; i++) { |
1501 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; | 1508 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; |
1509 | if (widget->size != sizeof(*widget)) { | ||
1510 | dev_err(tplg->dev, "ASoC: invalid widget size\n"); | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | |||
1502 | ret = soc_tplg_dapm_widget_create(tplg, widget); | 1514 | ret = soc_tplg_dapm_widget_create(tplg, widget); |
1503 | if (ret < 0) | 1515 | if (ret < 0) { |
1504 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", | 1516 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", |
1505 | widget->name); | 1517 | widget->name); |
1518 | return ret; | ||
1519 | } | ||
1506 | } | 1520 | } |
1507 | 1521 | ||
1508 | return 0; | 1522 | return 0; |
@@ -1586,6 +1600,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, | |||
1586 | return snd_soc_register_dai(tplg->comp, dai_drv); | 1600 | return snd_soc_register_dai(tplg->comp, dai_drv); |
1587 | } | 1601 | } |
1588 | 1602 | ||
1603 | /* create the FE DAI link */ | ||
1589 | static int soc_tplg_link_create(struct soc_tplg *tplg, | 1604 | static int soc_tplg_link_create(struct soc_tplg *tplg, |
1590 | struct snd_soc_tplg_pcm *pcm) | 1605 | struct snd_soc_tplg_pcm *pcm) |
1591 | { | 1606 | { |
@@ -1598,6 +1613,16 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, | |||
1598 | 1613 | ||
1599 | link->name = pcm->pcm_name; | 1614 | link->name = pcm->pcm_name; |
1600 | link->stream_name = pcm->pcm_name; | 1615 | link->stream_name = pcm->pcm_name; |
1616 | link->id = pcm->pcm_id; | ||
1617 | |||
1618 | link->cpu_dai_name = pcm->dai_name; | ||
1619 | link->codec_name = "snd-soc-dummy"; | ||
1620 | link->codec_dai_name = "snd-soc-dummy-dai"; | ||
1621 | |||
1622 | /* enable DPCM */ | ||
1623 | link->dynamic = 1; | ||
1624 | link->dpcm_playback = pcm->playback; | ||
1625 | link->dpcm_capture = pcm->capture; | ||
1601 | 1626 | ||
1602 | /* pass control to component driver for optional further init */ | 1627 | /* pass control to component driver for optional further init */ |
1603 | ret = soc_tplg_dai_link_load(tplg, link); | 1628 | ret = soc_tplg_dai_link_load(tplg, link); |
@@ -1639,8 +1664,6 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, | |||
1639 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) | 1664 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) |
1640 | return 0; | 1665 | return 0; |
1641 | 1666 | ||
1642 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; | ||
1643 | |||
1644 | if (soc_tplg_check_elem_count(tplg, | 1667 | if (soc_tplg_check_elem_count(tplg, |
1645 | sizeof(struct snd_soc_tplg_pcm), count, | 1668 | sizeof(struct snd_soc_tplg_pcm), count, |
1646 | hdr->payload_size, "PCM DAI")) { | 1669 | hdr->payload_size, "PCM DAI")) { |
@@ -1650,7 +1673,13 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, | |||
1650 | } | 1673 | } |
1651 | 1674 | ||
1652 | /* create the FE DAIs and DAI links */ | 1675 | /* create the FE DAIs and DAI links */ |
1676 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; | ||
1653 | for (i = 0; i < count; i++) { | 1677 | for (i = 0; i < count; i++) { |
1678 | if (pcm->size != sizeof(*pcm)) { | ||
1679 | dev_err(tplg->dev, "ASoC: invalid pcm size\n"); | ||
1680 | return -EINVAL; | ||
1681 | } | ||
1682 | |||
1654 | soc_tplg_pcm_create(tplg, pcm); | 1683 | soc_tplg_pcm_create(tplg, pcm); |
1655 | pcm++; | 1684 | pcm++; |
1656 | } | 1685 | } |
@@ -1670,6 +1699,11 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, | |||
1670 | return 0; | 1699 | return 0; |
1671 | 1700 | ||
1672 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; | 1701 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; |
1702 | if (manifest->size != sizeof(*manifest)) { | ||
1703 | dev_err(tplg->dev, "ASoC: invalid manifest size\n"); | ||
1704 | return -EINVAL; | ||
1705 | } | ||
1706 | |||
1673 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); | 1707 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); |
1674 | 1708 | ||
1675 | if (tplg->comp && tplg->ops && tplg->ops->manifest) | 1709 | if (tplg->comp && tplg->ops && tplg->ops->manifest) |
@@ -1686,6 +1720,14 @@ static int soc_valid_header(struct soc_tplg *tplg, | |||
1686 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) | 1720 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) |
1687 | return 0; | 1721 | return 0; |
1688 | 1722 | ||
1723 | if (hdr->size != sizeof(*hdr)) { | ||
1724 | dev_err(tplg->dev, | ||
1725 | "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n", | ||
1726 | hdr->type, soc_tplg_get_hdr_offset(tplg), | ||
1727 | tplg->fw->size); | ||
1728 | return -EINVAL; | ||
1729 | } | ||
1730 | |||
1689 | /* big endian firmware objects not supported atm */ | 1731 | /* big endian firmware objects not supported atm */ |
1690 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { | 1732 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { |
1691 | dev_err(tplg->dev, | 1733 | dev_err(tplg->dev, |
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 39bcefe5eea0..488ef4ed8fba 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c | |||
@@ -11,6 +11,142 @@ | |||
11 | #include "uniperif.h" | 11 | #include "uniperif.h" |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * User frame size shall be 2, 4, 6 or 8 32-bits words length | ||
15 | * (i.e. 8, 16, 24 or 32 bytes) | ||
16 | * This constraint comes from allowed values for | ||
17 | * UNIPERIF_I2S_FMT_NUM_CH register | ||
18 | */ | ||
19 | #define UNIPERIF_MAX_FRAME_SZ 0x20 | ||
20 | #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ) | ||
21 | |||
22 | int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
23 | unsigned int rx_mask, int slots, | ||
24 | int slot_width) | ||
25 | { | ||
26 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
27 | struct uniperif *uni = priv->dai_data.uni; | ||
28 | int i, frame_size, avail_slots; | ||
29 | |||
30 | if (!UNIPERIF_TYPE_IS_TDM(uni)) { | ||
31 | dev_err(uni->dev, "cpu dai not in tdm mode\n"); | ||
32 | return -EINVAL; | ||
33 | } | ||
34 | |||
35 | /* store info in unip context */ | ||
36 | uni->tdm_slot.slots = slots; | ||
37 | uni->tdm_slot.slot_width = slot_width; | ||
38 | /* unip is unidirectionnal */ | ||
39 | uni->tdm_slot.mask = (tx_mask != 0) ? tx_mask : rx_mask; | ||
40 | |||
41 | /* number of available timeslots */ | ||
42 | for (i = 0, avail_slots = 0; i < uni->tdm_slot.slots; i++) { | ||
43 | if ((uni->tdm_slot.mask >> i) & 0x01) | ||
44 | avail_slots++; | ||
45 | } | ||
46 | uni->tdm_slot.avail_slots = avail_slots; | ||
47 | |||
48 | /* frame size in bytes */ | ||
49 | frame_size = uni->tdm_slot.avail_slots * uni->tdm_slot.slot_width / 8; | ||
50 | |||
51 | /* check frame size is allowed */ | ||
52 | if ((frame_size > UNIPERIF_MAX_FRAME_SZ) || | ||
53 | (frame_size & ~(int)UNIPERIF_ALLOWED_FRAME_SZ)) { | ||
54 | dev_err(uni->dev, "frame size not allowed: %d bytes\n", | ||
55 | frame_size); | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, | ||
63 | struct snd_pcm_hw_rule *rule) | ||
64 | { | ||
65 | struct uniperif *uni = rule->private; | ||
66 | struct snd_interval t; | ||
67 | |||
68 | t.min = uni->tdm_slot.avail_slots; | ||
69 | t.max = uni->tdm_slot.avail_slots; | ||
70 | t.openmin = 0; | ||
71 | t.openmax = 0; | ||
72 | t.integer = 0; | ||
73 | |||
74 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
75 | } | ||
76 | |||
77 | int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, | ||
78 | struct snd_pcm_hw_rule *rule) | ||
79 | { | ||
80 | struct uniperif *uni = rule->private; | ||
81 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | ||
82 | u64 format; | ||
83 | |||
84 | switch (uni->tdm_slot.slot_width) { | ||
85 | case 16: | ||
86 | format = SNDRV_PCM_FMTBIT_S16_LE; | ||
87 | break; | ||
88 | case 32: | ||
89 | format = SNDRV_PCM_FMTBIT_S32_LE; | ||
90 | break; | ||
91 | default: | ||
92 | dev_err(uni->dev, "format not supported: %d bits\n", | ||
93 | uni->tdm_slot.slot_width); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | maskp->bits[0] &= (u_int32_t)format; | ||
98 | maskp->bits[1] &= (u_int32_t)(format >> 32); | ||
99 | /* clear remaining indexes */ | ||
100 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX - 64) / 8); | ||
101 | |||
102 | if (!maskp->bits[0] && !maskp->bits[1]) | ||
103 | return -EINVAL; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, | ||
109 | unsigned int *word_pos) | ||
110 | { | ||
111 | int slot_width = uni->tdm_slot.slot_width / 8; | ||
112 | int slots_num = uni->tdm_slot.slots; | ||
113 | unsigned int slots_mask = uni->tdm_slot.mask; | ||
114 | int i, j, k; | ||
115 | unsigned int word16_pos[4]; | ||
116 | |||
117 | /* word16_pos: | ||
118 | * word16_pos[0] = WORDX_LSB | ||
119 | * word16_pos[1] = WORDX_MSB, | ||
120 | * word16_pos[2] = WORDX+1_LSB | ||
121 | * word16_pos[3] = WORDX+1_MSB | ||
122 | */ | ||
123 | |||
124 | /* set unip word position */ | ||
125 | for (i = 0, j = 0, k = 0; (i < slots_num) && (k < WORD_MAX); i++) { | ||
126 | if ((slots_mask >> i) & 0x01) { | ||
127 | word16_pos[j] = i * slot_width; | ||
128 | |||
129 | if (slot_width == 4) { | ||
130 | word16_pos[j + 1] = word16_pos[j] + 2; | ||
131 | j++; | ||
132 | } | ||
133 | j++; | ||
134 | |||
135 | if (j > 3) { | ||
136 | word_pos[k] = word16_pos[1] | | ||
137 | (word16_pos[0] << 8) | | ||
138 | (word16_pos[3] << 16) | | ||
139 | (word16_pos[2] << 24); | ||
140 | j = 0; | ||
141 | k++; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* | ||
14 | * sti_uniperiph_dai_create_ctrl | 150 | * sti_uniperiph_dai_create_ctrl |
15 | * This function is used to create Ctrl associated to DAI but also pcm device. | 151 | * This function is used to create Ctrl associated to DAI but also pcm device. |
16 | * Request is done by front end to associate ctrl with pcm device id | 152 | * Request is done by front end to associate ctrl with pcm device id |
@@ -45,10 +181,16 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | |||
45 | struct snd_pcm_hw_params *params, | 181 | struct snd_pcm_hw_params *params, |
46 | struct snd_soc_dai *dai) | 182 | struct snd_soc_dai *dai) |
47 | { | 183 | { |
184 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
185 | struct uniperif *uni = priv->dai_data.uni; | ||
48 | struct snd_dmaengine_dai_dma_data *dma_data; | 186 | struct snd_dmaengine_dai_dma_data *dma_data; |
49 | int transfer_size; | 187 | int transfer_size; |
50 | 188 | ||
51 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | 189 | if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM) |
190 | /* transfer size = user frame size (in 32-bits FIFO cell) */ | ||
191 | transfer_size = snd_soc_params_to_frame_size(params) / 32; | ||
192 | else | ||
193 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | ||
52 | 194 | ||
53 | dma_data = snd_soc_dai_get_dma_data(dai, substream); | 195 | dma_data = snd_soc_dai_get_dma_data(dai, substream); |
54 | dma_data->maxburst = transfer_size; | 196 | dma_data->maxburst = transfer_size; |
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f0fd5a9944e9..eb9933c62ad6 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h | |||
@@ -25,7 +25,7 @@ | |||
25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) | 25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * AUD_UNIPERIF_SOFT_RST reg | 28 | * UNIPERIF_SOFT_RST reg |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 | 31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 |
@@ -50,7 +50,7 @@ | |||
50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) | 50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * AUD_UNIPERIF_FIFO_DATA reg | 53 | * UNIPERIF_FIFO_DATA reg |
54 | */ | 54 | */ |
55 | 55 | ||
56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 | 56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 |
@@ -58,7 +58,7 @@ | |||
58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) | 58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | 61 | * UNIPERIF_CHANNEL_STA_REGN reg |
62 | */ | 62 | */ |
63 | 63 | ||
64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | 64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) |
@@ -105,7 +105,7 @@ | |||
105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) | 105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) |
106 | 106 | ||
107 | /* | 107 | /* |
108 | * AUD_UNIPERIF_ITS reg | 108 | * UNIPERIF_ITS reg |
109 | */ | 109 | */ |
110 | 110 | ||
111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C | 111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C |
@@ -143,7 +143,7 @@ | |||
143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | 143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * AUD_UNIPERIF_ITS_BCLR reg | 146 | * UNIPERIF_ITS_BCLR reg |
147 | */ | 147 | */ |
148 | 148 | ||
149 | /* FIFO_ERROR */ | 149 | /* FIFO_ERROR */ |
@@ -160,7 +160,7 @@ | |||
160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) | 160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * AUD_UNIPERIF_ITM reg | 163 | * UNIPERIF_ITM reg |
164 | */ | 164 | */ |
165 | 165 | ||
166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 | 166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 |
@@ -188,7 +188,7 @@ | |||
188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | 188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) |
189 | 189 | ||
190 | /* | 190 | /* |
191 | * AUD_UNIPERIF_ITM_BCLR reg | 191 | * UNIPERIF_ITM_BCLR reg |
192 | */ | 192 | */ |
193 | 193 | ||
194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c | 194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c |
@@ -213,7 +213,7 @@ | |||
213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) | 213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) |
214 | 214 | ||
215 | /* | 215 | /* |
216 | * AUD_UNIPERIF_ITM_BSET reg | 216 | * UNIPERIF_ITM_BSET reg |
217 | */ | 217 | */ |
218 | 218 | ||
219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 | 219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 |
@@ -767,7 +767,7 @@ | |||
767 | SET_UNIPERIF_REG(ip, \ | 767 | SET_UNIPERIF_REG(ip, \ |
768 | UNIPERIF_CTRL_OFFSET(ip), \ | 768 | UNIPERIF_CTRL_OFFSET(ip), \ |
769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ | 769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ |
770 | CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) | 770 | UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) |
771 | 771 | ||
772 | /* UNDERFLOW_REC_WINDOW */ | 772 | /* UNDERFLOW_REC_WINDOW */ |
773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 | 773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 |
@@ -1046,7 +1046,7 @@ | |||
1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) | 1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) |
1047 | 1047 | ||
1048 | /* | 1048 | /* |
1049 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | 1049 | * UNIPERIF_CHANNEL_STA_REGN reg |
1050 | */ | 1050 | */ |
1051 | 1051 | ||
1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | 1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) |
@@ -1057,7 +1057,7 @@ | |||
1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) | 1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) |
1058 | 1058 | ||
1059 | /* | 1059 | /* |
1060 | * AUD_UNIPERIF_USER_VALIDITY reg | 1060 | * UNIPERIF_USER_VALIDITY reg |
1061 | */ | 1061 | */ |
1062 | 1062 | ||
1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 | 1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 |
@@ -1101,12 +1101,136 @@ | |||
1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) | 1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) |
1102 | 1102 | ||
1103 | /* | 1103 | /* |
1104 | * UNIPERIF_TDM_ENABLE | ||
1105 | */ | ||
1106 | #define UNIPERIF_TDM_ENABLE_OFFSET(ip) 0x0118 | ||
1107 | #define GET_UNIPERIF_TDM_ENABLE(ip) \ | ||
1108 | readl_relaxed(ip->base + UNIPERIF_TDM_ENABLE_OFFSET(ip)) | ||
1109 | #define SET_UNIPERIF_TDM_ENABLE(ip, value) \ | ||
1110 | writel_relaxed(value, ip->base + UNIPERIF_TDM_ENABLE_OFFSET(ip)) | ||
1111 | |||
1112 | /* TDM_ENABLE */ | ||
1113 | #define UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip) 0x0 | ||
1114 | #define UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip) 0x1 | ||
1115 | #define GET_UNIPERIF_TDM_ENABLE_EN_TDM(ip) \ | ||
1116 | GET_UNIPERIF_REG(ip, \ | ||
1117 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1118 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1119 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip)) | ||
1120 | #define SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(ip) \ | ||
1121 | SET_UNIPERIF_REG(ip, \ | ||
1122 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1123 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1124 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip), 1) | ||
1125 | #define SET_UNIPERIF_TDM_ENABLE_TDM_DISABLE(ip) \ | ||
1126 | SET_UNIPERIF_REG(ip, \ | ||
1127 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1128 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1129 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip), 0) | ||
1130 | |||
1131 | /* | ||
1132 | * UNIPERIF_TDM_FS_REF_FREQ | ||
1133 | */ | ||
1134 | #define UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip) 0x011c | ||
1135 | #define GET_UNIPERIF_TDM_FS_REF_FREQ(ip) \ | ||
1136 | readl_relaxed(ip->base + UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip)) | ||
1137 | #define SET_UNIPERIF_TDM_FS_REF_FREQ(ip, value) \ | ||
1138 | writel_relaxed(value, ip->base + \ | ||
1139 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip)) | ||
1140 | |||
1141 | /* REF_FREQ */ | ||
1142 | #define UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip) 0x0 | ||
1143 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip) 0 | ||
1144 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip) 1 | ||
1145 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip) 2 | ||
1146 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip) 3 | ||
1147 | #define UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip) 0x3 | ||
1148 | #define GET_UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ(ip) \ | ||
1149 | GET_UNIPERIF_REG(ip, \ | ||
1150 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1151 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1152 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip)) | ||
1153 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip) \ | ||
1154 | SET_UNIPERIF_REG(ip, \ | ||
1155 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1156 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1157 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1158 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip)) | ||
1159 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip) \ | ||
1160 | SET_UNIPERIF_REG(ip, \ | ||
1161 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1162 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1163 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1164 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip)) | ||
1165 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip) \ | ||
1166 | SET_UNIPERIF_REG(ip, \ | ||
1167 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1168 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1169 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1170 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip)) | ||
1171 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip) \ | ||
1172 | SET_UNIPERIF_REG(ip, \ | ||
1173 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1174 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1175 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1176 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip)) | ||
1177 | |||
1178 | /* | ||
1179 | * UNIPERIF_TDM_FS_REF_DIV | ||
1180 | */ | ||
1181 | #define UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip) 0x0120 | ||
1182 | #define GET_UNIPERIF_TDM_FS_REF_DIV(ip) \ | ||
1183 | readl_relaxed(ip->base + UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip)) | ||
1184 | #define SET_UNIPERIF_TDM_FS_REF_DIV(ip, value) \ | ||
1185 | writel_relaxed(value, ip->base + \ | ||
1186 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip)) | ||
1187 | |||
1188 | /* NUM_TIMESLOT */ | ||
1189 | #define UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip) 0x0 | ||
1190 | #define UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip) 0xff | ||
1191 | #define GET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(ip) \ | ||
1192 | GET_UNIPERIF_REG(ip, \ | ||
1193 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip), \ | ||
1194 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip), \ | ||
1195 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip)) | ||
1196 | #define SET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(ip, value) \ | ||
1197 | SET_UNIPERIF_REG(ip, \ | ||
1198 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip), \ | ||
1199 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip), \ | ||
1200 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip), value) | ||
1201 | |||
1202 | /* | ||
1203 | * UNIPERIF_TDM_WORD_POS_X_Y | ||
1204 | * 32 bits of UNIPERIF_TDM_WORD_POS_X_Y register shall be set in 1 shot | ||
1205 | */ | ||
1206 | #define UNIPERIF_TDM_WORD_POS_1_2_OFFSET(ip) 0x013c | ||
1207 | #define UNIPERIF_TDM_WORD_POS_3_4_OFFSET(ip) 0x0140 | ||
1208 | #define UNIPERIF_TDM_WORD_POS_5_6_OFFSET(ip) 0x0144 | ||
1209 | #define UNIPERIF_TDM_WORD_POS_7_8_OFFSET(ip) 0x0148 | ||
1210 | #define GET_UNIPERIF_TDM_WORD_POS(ip, words) \ | ||
1211 | readl_relaxed(ip->base + UNIPERIF_TDM_WORD_POS_##words##_OFFSET(ip)) | ||
1212 | #define SET_UNIPERIF_TDM_WORD_POS(ip, words, value) \ | ||
1213 | writel_relaxed(value, ip->base + \ | ||
1214 | UNIPERIF_TDM_WORD_POS_##words##_OFFSET(ip)) | ||
1215 | /* | ||
1104 | * uniperipheral IP capabilities | 1216 | * uniperipheral IP capabilities |
1105 | */ | 1217 | */ |
1106 | 1218 | ||
1107 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ | 1219 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ |
1108 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ | 1220 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ |
1109 | 1221 | ||
1222 | #define UNIPERIF_TYPE_IS_HDMI(p) \ | ||
1223 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_HDMI) | ||
1224 | #define UNIPERIF_TYPE_IS_PCM(p) \ | ||
1225 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_PCM) | ||
1226 | #define UNIPERIF_TYPE_IS_SPDIF(p) \ | ||
1227 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_SPDIF) | ||
1228 | #define UNIPERIF_TYPE_IS_IEC958(p) \ | ||
1229 | (UNIPERIF_TYPE_IS_HDMI(p) || \ | ||
1230 | UNIPERIF_TYPE_IS_SPDIF(p)) | ||
1231 | #define UNIPERIF_TYPE_IS_TDM(p) \ | ||
1232 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_TDM) | ||
1233 | |||
1110 | /* | 1234 | /* |
1111 | * Uniperipheral IP revisions | 1235 | * Uniperipheral IP revisions |
1112 | */ | 1236 | */ |
@@ -1125,10 +1249,11 @@ enum uniperif_version { | |||
1125 | }; | 1249 | }; |
1126 | 1250 | ||
1127 | enum uniperif_type { | 1251 | enum uniperif_type { |
1128 | SND_ST_UNIPERIF_PLAYER_TYPE_NONE, | 1252 | SND_ST_UNIPERIF_TYPE_NONE, |
1129 | SND_ST_UNIPERIF_PLAYER_TYPE_HDMI, | 1253 | SND_ST_UNIPERIF_TYPE_HDMI, |
1130 | SND_ST_UNIPERIF_PLAYER_TYPE_PCM, | 1254 | SND_ST_UNIPERIF_TYPE_PCM, |
1131 | SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF | 1255 | SND_ST_UNIPERIF_TYPE_SPDIF, |
1256 | SND_ST_UNIPERIF_TYPE_TDM | ||
1132 | }; | 1257 | }; |
1133 | 1258 | ||
1134 | enum uniperif_state { | 1259 | enum uniperif_state { |
@@ -1145,9 +1270,17 @@ enum uniperif_iec958_encoding_mode { | |||
1145 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED | 1270 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED |
1146 | }; | 1271 | }; |
1147 | 1272 | ||
1273 | enum uniperif_word_pos { | ||
1274 | WORD_1_2, | ||
1275 | WORD_3_4, | ||
1276 | WORD_5_6, | ||
1277 | WORD_7_8, | ||
1278 | WORD_MAX | ||
1279 | }; | ||
1280 | |||
1148 | struct uniperif_info { | 1281 | struct uniperif_info { |
1149 | int id; /* instance value of the uniperipheral IP */ | 1282 | int id; /* instance value of the uniperipheral IP */ |
1150 | enum uniperif_type player_type; | 1283 | enum uniperif_type type; |
1151 | int underflow_enabled; /* Underflow recovery mode */ | 1284 | int underflow_enabled; /* Underflow recovery mode */ |
1152 | }; | 1285 | }; |
1153 | 1286 | ||
@@ -1156,12 +1289,20 @@ struct uniperif_iec958_settings { | |||
1156 | struct snd_aes_iec958 iec958; | 1289 | struct snd_aes_iec958 iec958; |
1157 | }; | 1290 | }; |
1158 | 1291 | ||
1292 | struct dai_tdm_slot { | ||
1293 | unsigned int mask; | ||
1294 | int slots; | ||
1295 | int slot_width; | ||
1296 | unsigned int avail_slots; | ||
1297 | }; | ||
1298 | |||
1159 | struct uniperif { | 1299 | struct uniperif { |
1160 | /* System information */ | 1300 | /* System information */ |
1161 | struct uniperif_info *info; | 1301 | struct uniperif_info *info; |
1162 | struct device *dev; | 1302 | struct device *dev; |
1163 | int ver; /* IP version, used by register access macros */ | 1303 | int ver; /* IP version, used by register access macros */ |
1164 | struct regmap_field *clk_sel; | 1304 | struct regmap_field *clk_sel; |
1305 | struct regmap_field *valid_sel; | ||
1165 | 1306 | ||
1166 | /* capabilities */ | 1307 | /* capabilities */ |
1167 | const struct snd_pcm_hardware *hw; | 1308 | const struct snd_pcm_hardware *hw; |
@@ -1192,6 +1333,7 @@ struct uniperif { | |||
1192 | 1333 | ||
1193 | /* dai properties */ | 1334 | /* dai properties */ |
1194 | unsigned int daifmt; | 1335 | unsigned int daifmt; |
1336 | struct dai_tdm_slot tdm_slot; | ||
1195 | 1337 | ||
1196 | /* DAI callbacks */ | 1338 | /* DAI callbacks */ |
1197 | const struct snd_soc_dai_ops *dai_ops; | 1339 | const struct snd_soc_dai_ops *dai_ops; |
@@ -1209,6 +1351,28 @@ struct sti_uniperiph_data { | |||
1209 | struct sti_uniperiph_dai dai_data; | 1351 | struct sti_uniperiph_dai dai_data; |
1210 | }; | 1352 | }; |
1211 | 1353 | ||
1354 | static const struct snd_pcm_hardware uni_tdm_hw = { | ||
1355 | .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
1356 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | | ||
1357 | SNDRV_PCM_INFO_MMAP_VALID, | ||
1358 | |||
1359 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
1360 | |||
1361 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
1362 | .rate_min = 8000, | ||
1363 | .rate_max = 48000, | ||
1364 | |||
1365 | .channels_min = 1, | ||
1366 | .channels_max = 32, | ||
1367 | |||
1368 | .periods_min = 2, | ||
1369 | .periods_max = 10, | ||
1370 | |||
1371 | .period_bytes_min = 128, | ||
1372 | .period_bytes_max = 64 * PAGE_SIZE, | ||
1373 | .buffer_bytes_max = 256 * PAGE_SIZE | ||
1374 | }; | ||
1375 | |||
1212 | /* uniperiph player*/ | 1376 | /* uniperiph player*/ |
1213 | int uni_player_init(struct platform_device *pdev, | 1377 | int uni_player_init(struct platform_device *pdev, |
1214 | struct uniperif *uni_player); | 1378 | struct uniperif *uni_player); |
@@ -1226,4 +1390,28 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | |||
1226 | struct snd_pcm_hw_params *params, | 1390 | struct snd_pcm_hw_params *params, |
1227 | struct snd_soc_dai *dai); | 1391 | struct snd_soc_dai *dai); |
1228 | 1392 | ||
1393 | static inline int sti_uniperiph_get_user_frame_size( | ||
1394 | struct snd_pcm_runtime *runtime) | ||
1395 | { | ||
1396 | return (runtime->channels * snd_pcm_format_width(runtime->format) / 8); | ||
1397 | } | ||
1398 | |||
1399 | static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni) | ||
1400 | { | ||
1401 | return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8); | ||
1402 | } | ||
1403 | |||
1404 | int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
1405 | unsigned int rx_mask, int slots, | ||
1406 | int slot_width); | ||
1407 | |||
1408 | int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, | ||
1409 | unsigned int *word_pos); | ||
1410 | |||
1411 | int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, | ||
1412 | struct snd_pcm_hw_rule *rule); | ||
1413 | |||
1414 | int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, | ||
1415 | struct snd_pcm_hw_rule *rule); | ||
1416 | |||
1229 | #endif | 1417 | #endif |
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 7aca6b92f718..ee1c7c245bc7 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c | |||
@@ -21,23 +21,14 @@ | |||
21 | 21 | ||
22 | /* sys config registers definitions */ | 22 | /* sys config registers definitions */ |
23 | #define SYS_CFG_AUDIO_GLUE 0xA4 | 23 | #define SYS_CFG_AUDIO_GLUE 0xA4 |
24 | #define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 | ||
25 | 24 | ||
26 | /* | 25 | /* |
27 | * Driver specific types. | 26 | * Driver specific types. |
28 | */ | 27 | */ |
29 | #define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ | ||
30 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) | ||
31 | #define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ | ||
32 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) | ||
33 | #define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ | ||
34 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) | ||
35 | #define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ | ||
36 | (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ | ||
37 | UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) | ||
38 | 28 | ||
39 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 | 29 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 |
40 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 | 30 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 |
31 | #define UNIPERIF_PLAYER_I2S_OUT 1 /* player id connected to I2S/TDM TX bus */ | ||
41 | 32 | ||
42 | /* | 33 | /* |
43 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to | 34 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to |
@@ -444,18 +435,11 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
444 | 435 | ||
445 | /* Force slot width to 32 in I2S mode (HW constraint) */ | 436 | /* Force slot width to 32 in I2S mode (HW constraint) */ |
446 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == | 437 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == |
447 | SND_SOC_DAIFMT_I2S) { | 438 | SND_SOC_DAIFMT_I2S) |
448 | slot_width = 32; | 439 | slot_width = 32; |
449 | } else { | 440 | else |
450 | switch (runtime->format) { | 441 | slot_width = snd_pcm_format_width(runtime->format); |
451 | case SNDRV_PCM_FORMAT_S16_LE: | 442 | |
452 | slot_width = 16; | ||
453 | break; | ||
454 | default: | ||
455 | slot_width = 32; | ||
456 | break; | ||
457 | } | ||
458 | } | ||
459 | output_frame_size = slot_width * runtime->channels; | 443 | output_frame_size = slot_width * runtime->channels; |
460 | 444 | ||
461 | clk_div = player->mclk / runtime->rate; | 445 | clk_div = player->mclk / runtime->rate; |
@@ -530,7 +514,6 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
530 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); | 514 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); |
531 | 515 | ||
532 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | 516 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); |
533 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); | ||
534 | 517 | ||
535 | /* No iec958 formatting as outputting to DAC */ | 518 | /* No iec958 formatting as outputting to DAC */ |
536 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); | 519 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); |
@@ -538,6 +521,55 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
538 | return 0; | 521 | return 0; |
539 | } | 522 | } |
540 | 523 | ||
524 | static int uni_player_prepare_tdm(struct uniperif *player, | ||
525 | struct snd_pcm_runtime *runtime) | ||
526 | { | ||
527 | int tdm_frame_size; /* unip tdm frame size in bytes */ | ||
528 | int user_frame_size; /* user tdm frame size in bytes */ | ||
529 | /* default unip TDM_WORD_POS_X_Y */ | ||
530 | unsigned int word_pos[4] = { | ||
531 | 0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A}; | ||
532 | int freq, ret; | ||
533 | |||
534 | tdm_frame_size = | ||
535 | sti_uniperiph_get_unip_tdm_frame_size(player); | ||
536 | user_frame_size = | ||
537 | sti_uniperiph_get_user_frame_size(runtime); | ||
538 | |||
539 | /* fix 16/0 format */ | ||
540 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); | ||
541 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); | ||
542 | |||
543 | /* number of words inserted on the TDM line */ | ||
544 | SET_UNIPERIF_I2S_FMT_NUM_CH(player, user_frame_size / 4 / 2); | ||
545 | |||
546 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | ||
547 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); | ||
548 | |||
549 | /* Enable the tdm functionality */ | ||
550 | SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(player); | ||
551 | |||
552 | /* number of 8 bits timeslots avail in unip tdm frame */ | ||
553 | SET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(player, tdm_frame_size); | ||
554 | |||
555 | /* set the timeslot allocation for words in FIFO */ | ||
556 | sti_uniperiph_get_tdm_word_pos(player, word_pos); | ||
557 | SET_UNIPERIF_TDM_WORD_POS(player, 1_2, word_pos[WORD_1_2]); | ||
558 | SET_UNIPERIF_TDM_WORD_POS(player, 3_4, word_pos[WORD_3_4]); | ||
559 | SET_UNIPERIF_TDM_WORD_POS(player, 5_6, word_pos[WORD_5_6]); | ||
560 | SET_UNIPERIF_TDM_WORD_POS(player, 7_8, word_pos[WORD_7_8]); | ||
561 | |||
562 | /* set unip clk rate (not done vai set_sysclk ops) */ | ||
563 | freq = runtime->rate * tdm_frame_size * 8; | ||
564 | mutex_lock(&player->ctrl_lock); | ||
565 | ret = uni_player_clk_set_rate(player, freq); | ||
566 | if (!ret) | ||
567 | player->mclk = freq; | ||
568 | mutex_unlock(&player->ctrl_lock); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
541 | /* | 573 | /* |
542 | * ALSA uniperipheral iec958 controls | 574 | * ALSA uniperipheral iec958 controls |
543 | */ | 575 | */ |
@@ -668,11 +700,29 @@ static int uni_player_startup(struct snd_pcm_substream *substream, | |||
668 | { | 700 | { |
669 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 701 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
670 | struct uniperif *player = priv->dai_data.uni; | 702 | struct uniperif *player = priv->dai_data.uni; |
703 | int ret; | ||
704 | |||
671 | player->substream = substream; | 705 | player->substream = substream; |
672 | 706 | ||
673 | player->clk_adj = 0; | 707 | player->clk_adj = 0; |
674 | 708 | ||
675 | return 0; | 709 | if (!UNIPERIF_TYPE_IS_TDM(player)) |
710 | return 0; | ||
711 | |||
712 | /* refine hw constraint in tdm mode */ | ||
713 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
714 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
715 | sti_uniperiph_fix_tdm_chan, | ||
716 | player, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
717 | -1); | ||
718 | if (ret < 0) | ||
719 | return ret; | ||
720 | |||
721 | return snd_pcm_hw_rule_add(substream->runtime, 0, | ||
722 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
723 | sti_uniperiph_fix_tdm_format, | ||
724 | player, SNDRV_PCM_HW_PARAM_FORMAT, | ||
725 | -1); | ||
676 | } | 726 | } |
677 | 727 | ||
678 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 728 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
@@ -682,7 +732,7 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
682 | struct uniperif *player = priv->dai_data.uni; | 732 | struct uniperif *player = priv->dai_data.uni; |
683 | int ret; | 733 | int ret; |
684 | 734 | ||
685 | if (dir == SND_SOC_CLOCK_IN) | 735 | if (UNIPERIF_TYPE_IS_TDM(player) || (dir == SND_SOC_CLOCK_IN)) |
686 | return 0; | 736 | return 0; |
687 | 737 | ||
688 | if (clk_id != 0) | 738 | if (clk_id != 0) |
@@ -714,7 +764,13 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, | |||
714 | } | 764 | } |
715 | 765 | ||
716 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | 766 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ |
717 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | 767 | if (player->info->type == SND_ST_UNIPERIF_TYPE_TDM) { |
768 | /* transfer size = user frame size (in 32 bits FIFO cell) */ | ||
769 | transfer_size = | ||
770 | sti_uniperiph_get_user_frame_size(runtime) / 4; | ||
771 | } else { | ||
772 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
773 | } | ||
718 | 774 | ||
719 | /* Calculate number of empty cells available before asserting DREQ */ | 775 | /* Calculate number of empty cells available before asserting DREQ */ |
720 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { | 776 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { |
@@ -738,16 +794,19 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, | |||
738 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); | 794 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); |
739 | 795 | ||
740 | /* Uniperipheral setup depends on player type */ | 796 | /* Uniperipheral setup depends on player type */ |
741 | switch (player->info->player_type) { | 797 | switch (player->info->type) { |
742 | case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: | 798 | case SND_ST_UNIPERIF_TYPE_HDMI: |
743 | ret = uni_player_prepare_iec958(player, runtime); | 799 | ret = uni_player_prepare_iec958(player, runtime); |
744 | break; | 800 | break; |
745 | case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: | 801 | case SND_ST_UNIPERIF_TYPE_PCM: |
746 | ret = uni_player_prepare_pcm(player, runtime); | 802 | ret = uni_player_prepare_pcm(player, runtime); |
747 | break; | 803 | break; |
748 | case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: | 804 | case SND_ST_UNIPERIF_TYPE_SPDIF: |
749 | ret = uni_player_prepare_iec958(player, runtime); | 805 | ret = uni_player_prepare_iec958(player, runtime); |
750 | break; | 806 | break; |
807 | case SND_ST_UNIPERIF_TYPE_TDM: | ||
808 | ret = uni_player_prepare_tdm(player, runtime); | ||
809 | break; | ||
751 | default: | 810 | default: |
752 | dev_err(player->dev, "invalid player type"); | 811 | dev_err(player->dev, "invalid player type"); |
753 | return -EINVAL; | 812 | return -EINVAL; |
@@ -852,8 +911,8 @@ static int uni_player_start(struct uniperif *player) | |||
852 | * will not take affect and hang the player. | 911 | * will not take affect and hang the player. |
853 | */ | 912 | */ |
854 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | 913 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) |
855 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) | 914 | if (UNIPERIF_TYPE_IS_IEC958(player)) |
856 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); | 915 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); |
857 | 916 | ||
858 | /* Force channel status update (no update if clk disable) */ | 917 | /* Force channel status update (no update if clk disable) */ |
859 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | 918 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) |
@@ -954,27 +1013,30 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, | |||
954 | player->substream = NULL; | 1013 | player->substream = NULL; |
955 | } | 1014 | } |
956 | 1015 | ||
957 | static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, | 1016 | static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, |
958 | struct uniperif *player) | 1017 | struct uniperif *player) |
959 | { | 1018 | { |
960 | int bit_offset; | ||
961 | struct device_node *node = pdev->dev.of_node; | 1019 | struct device_node *node = pdev->dev.of_node; |
962 | struct regmap *regmap; | 1020 | struct regmap *regmap; |
963 | 1021 | struct reg_field regfield[2] = { | |
964 | bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; | 1022 | /* PCM_CLK_SEL */ |
1023 | REG_FIELD(SYS_CFG_AUDIO_GLUE, | ||
1024 | 8 + player->info->id, | ||
1025 | 8 + player->info->id), | ||
1026 | /* PCMP_VALID_SEL */ | ||
1027 | REG_FIELD(SYS_CFG_AUDIO_GLUE, 0, 1) | ||
1028 | }; | ||
965 | 1029 | ||
966 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); | 1030 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); |
967 | 1031 | ||
968 | if (regmap) { | 1032 | if (!regmap) { |
969 | struct reg_field regfield = | ||
970 | REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); | ||
971 | |||
972 | player->clk_sel = regmap_field_alloc(regmap, regfield); | ||
973 | } else { | ||
974 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); | 1033 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); |
975 | return -EINVAL; | 1034 | return -EINVAL; |
976 | } | 1035 | } |
977 | 1036 | ||
1037 | player->clk_sel = regmap_field_alloc(regmap, regfield[0]); | ||
1038 | player->valid_sel = regmap_field_alloc(regmap, regfield[1]); | ||
1039 | |||
978 | return 0; | 1040 | return 0; |
979 | } | 1041 | } |
980 | 1042 | ||
@@ -1012,19 +1074,21 @@ static int uni_player_parse_dt(struct platform_device *pdev, | |||
1012 | } | 1074 | } |
1013 | 1075 | ||
1014 | if (strcasecmp(mode, "hdmi") == 0) | 1076 | if (strcasecmp(mode, "hdmi") == 0) |
1015 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; | 1077 | info->type = SND_ST_UNIPERIF_TYPE_HDMI; |
1016 | else if (strcasecmp(mode, "pcm") == 0) | 1078 | else if (strcasecmp(mode, "pcm") == 0) |
1017 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; | 1079 | info->type = SND_ST_UNIPERIF_TYPE_PCM; |
1018 | else if (strcasecmp(mode, "spdif") == 0) | 1080 | else if (strcasecmp(mode, "spdif") == 0) |
1019 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; | 1081 | info->type = SND_ST_UNIPERIF_TYPE_SPDIF; |
1082 | else if (strcasecmp(mode, "tdm") == 0) | ||
1083 | info->type = SND_ST_UNIPERIF_TYPE_TDM; | ||
1020 | else | 1084 | else |
1021 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; | 1085 | info->type = SND_ST_UNIPERIF_TYPE_NONE; |
1022 | 1086 | ||
1023 | /* Save the info structure */ | 1087 | /* Save the info structure */ |
1024 | player->info = info; | 1088 | player->info = info; |
1025 | 1089 | ||
1026 | /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ | 1090 | /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ |
1027 | if (uni_player_parse_dt_clk_glue(pdev, player)) | 1091 | if (uni_player_parse_dt_audio_glue(pdev, player)) |
1028 | return -EINVAL; | 1092 | return -EINVAL; |
1029 | 1093 | ||
1030 | return 0; | 1094 | return 0; |
@@ -1037,7 +1101,8 @@ static const struct snd_soc_dai_ops uni_player_dai_ops = { | |||
1037 | .trigger = uni_player_trigger, | 1101 | .trigger = uni_player_trigger, |
1038 | .hw_params = sti_uniperiph_dai_hw_params, | 1102 | .hw_params = sti_uniperiph_dai_hw_params, |
1039 | .set_fmt = sti_uniperiph_dai_set_fmt, | 1103 | .set_fmt = sti_uniperiph_dai_set_fmt, |
1040 | .set_sysclk = uni_player_set_sysclk | 1104 | .set_sysclk = uni_player_set_sysclk, |
1105 | .set_tdm_slot = sti_uniperiph_set_tdm_slot | ||
1041 | }; | 1106 | }; |
1042 | 1107 | ||
1043 | int uni_player_init(struct platform_device *pdev, | 1108 | int uni_player_init(struct platform_device *pdev, |
@@ -1047,7 +1112,6 @@ int uni_player_init(struct platform_device *pdev, | |||
1047 | 1112 | ||
1048 | player->dev = &pdev->dev; | 1113 | player->dev = &pdev->dev; |
1049 | player->state = UNIPERIF_STATE_STOPPED; | 1114 | player->state = UNIPERIF_STATE_STOPPED; |
1050 | player->hw = &uni_player_pcm_hw; | ||
1051 | player->dai_ops = &uni_player_dai_ops; | 1115 | player->dai_ops = &uni_player_dai_ops; |
1052 | 1116 | ||
1053 | ret = uni_player_parse_dt(pdev, player); | 1117 | ret = uni_player_parse_dt(pdev, player); |
@@ -1057,6 +1121,11 @@ int uni_player_init(struct platform_device *pdev, | |||
1057 | return ret; | 1121 | return ret; |
1058 | } | 1122 | } |
1059 | 1123 | ||
1124 | if (UNIPERIF_TYPE_IS_TDM(player)) | ||
1125 | player->hw = &uni_tdm_hw; | ||
1126 | else | ||
1127 | player->hw = &uni_player_pcm_hw; | ||
1128 | |||
1060 | /* Get uniperif resource */ | 1129 | /* Get uniperif resource */ |
1061 | player->clk = of_clk_get(pdev->dev.of_node, 0); | 1130 | player->clk = of_clk_get(pdev->dev.of_node, 0); |
1062 | if (IS_ERR(player->clk)) | 1131 | if (IS_ERR(player->clk)) |
@@ -1073,6 +1142,17 @@ int uni_player_init(struct platform_device *pdev, | |||
1073 | } | 1142 | } |
1074 | } | 1143 | } |
1075 | 1144 | ||
1145 | /* connect to I2S/TDM TX bus */ | ||
1146 | if (player->valid_sel && | ||
1147 | (player->info->id == UNIPERIF_PLAYER_I2S_OUT)) { | ||
1148 | ret = regmap_field_write(player->valid_sel, player->info->id); | ||
1149 | if (ret) { | ||
1150 | dev_err(player->dev, | ||
1151 | "%s: unable to connect to tdm bus", __func__); | ||
1152 | return ret; | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1076 | ret = devm_request_irq(&pdev->dev, player->irq, | 1156 | ret = devm_request_irq(&pdev->dev, player->irq, |
1077 | uni_player_irq_handler, IRQF_SHARED, | 1157 | uni_player_irq_handler, IRQF_SHARED, |
1078 | dev_name(&pdev->dev), player); | 1158 | dev_name(&pdev->dev), player); |
@@ -1087,7 +1167,7 @@ int uni_player_init(struct platform_device *pdev, | |||
1087 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); | 1167 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); |
1088 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); | 1168 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); |
1089 | 1169 | ||
1090 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { | 1170 | if (UNIPERIF_TYPE_IS_IEC958(player)) { |
1091 | /* Set default iec958 status bits */ | 1171 | /* Set default iec958 status bits */ |
1092 | 1172 | ||
1093 | /* Consumer, PCM, copyright, 2ch, mode 0 */ | 1173 | /* Consumer, PCM, copyright, 2ch, mode 0 */ |
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 8a0eb2050169..eb74a328c928 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c | |||
@@ -73,55 +73,10 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) | |||
73 | return ret; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | 76 | static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, |
77 | struct snd_soc_dai *dai) | 77 | struct uniperif *reader) |
78 | { | 78 | { |
79 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
80 | struct uniperif *reader = priv->dai_data.uni; | ||
81 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
82 | int transfer_size, trigger_limit; | ||
83 | int slot_width; | 79 | int slot_width; |
84 | int count = 10; | ||
85 | |||
86 | /* The reader should be stopped */ | ||
87 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
88 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
89 | reader->state); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
94 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
95 | |||
96 | /* Calculate number of empty cells available before asserting DREQ */ | ||
97 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
98 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
99 | else | ||
100 | /* | ||
101 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
102 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
103 | * from OFF or STANDBY to AUDIO DATA. | ||
104 | */ | ||
105 | trigger_limit = transfer_size; | ||
106 | |||
107 | /* Trigger limit must be an even number */ | ||
108 | if ((!trigger_limit % 2) || | ||
109 | (trigger_limit != 1 && transfer_size % 2) || | ||
110 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
111 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
116 | |||
117 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | ||
118 | case SND_SOC_DAIFMT_IB_IF: | ||
119 | case SND_SOC_DAIFMT_NB_IF: | ||
120 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
121 | break; | ||
122 | default: | ||
123 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
124 | } | ||
125 | 80 | ||
126 | /* Force slot width to 32 in I2S mode */ | 81 | /* Force slot width to 32 in I2S mode */ |
127 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) | 82 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) |
@@ -173,6 +128,109 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, | |||
173 | return -EINVAL; | 128 | return -EINVAL; |
174 | } | 129 | } |
175 | 130 | ||
131 | /* Number of channels must be even */ | ||
132 | if ((runtime->channels % 2) || (runtime->channels < 2) || | ||
133 | (runtime->channels > 10)) { | ||
134 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
139 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int uni_reader_prepare_tdm(struct snd_pcm_runtime *runtime, | ||
145 | struct uniperif *reader) | ||
146 | { | ||
147 | int frame_size; /* user tdm frame size in bytes */ | ||
148 | /* default unip TDM_WORD_POS_X_Y */ | ||
149 | unsigned int word_pos[4] = { | ||
150 | 0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A}; | ||
151 | |||
152 | frame_size = sti_uniperiph_get_user_frame_size(runtime); | ||
153 | |||
154 | /* fix 16/0 format */ | ||
155 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader); | ||
156 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader); | ||
157 | |||
158 | /* number of words inserted on the TDM line */ | ||
159 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, frame_size / 4 / 2); | ||
160 | |||
161 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
162 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | ||
163 | SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(reader); | ||
164 | |||
165 | /* | ||
166 | * set the timeslots allocation for words in FIFO | ||
167 | * | ||
168 | * HW bug: (LSB word < MSB word) => this config is not possible | ||
169 | * So if we want (LSB word < MSB) word, then it shall be | ||
170 | * handled by user | ||
171 | */ | ||
172 | sti_uniperiph_get_tdm_word_pos(reader, word_pos); | ||
173 | SET_UNIPERIF_TDM_WORD_POS(reader, 1_2, word_pos[WORD_1_2]); | ||
174 | SET_UNIPERIF_TDM_WORD_POS(reader, 3_4, word_pos[WORD_3_4]); | ||
175 | SET_UNIPERIF_TDM_WORD_POS(reader, 5_6, word_pos[WORD_5_6]); | ||
176 | SET_UNIPERIF_TDM_WORD_POS(reader, 7_8, word_pos[WORD_7_8]); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | ||
182 | struct snd_soc_dai *dai) | ||
183 | { | ||
184 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
185 | struct uniperif *reader = priv->dai_data.uni; | ||
186 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
187 | int transfer_size, trigger_limit, ret; | ||
188 | int count = 10; | ||
189 | |||
190 | /* The reader should be stopped */ | ||
191 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
192 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
193 | reader->state); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
198 | if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) { | ||
199 | /* transfer size = unip frame size (in 32 bits FIFO cell) */ | ||
200 | transfer_size = | ||
201 | sti_uniperiph_get_user_frame_size(runtime) / 4; | ||
202 | } else { | ||
203 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
204 | } | ||
205 | |||
206 | /* Calculate number of empty cells available before asserting DREQ */ | ||
207 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
208 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
209 | else | ||
210 | /* | ||
211 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
212 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
213 | * from OFF or STANDBY to AUDIO DATA. | ||
214 | */ | ||
215 | trigger_limit = transfer_size; | ||
216 | |||
217 | /* Trigger limit must be an even number */ | ||
218 | if ((!trigger_limit % 2) || | ||
219 | (trigger_limit != 1 && transfer_size % 2) || | ||
220 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
221 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
226 | |||
227 | if (UNIPERIF_TYPE_IS_TDM(reader)) | ||
228 | ret = uni_reader_prepare_tdm(runtime, reader); | ||
229 | else | ||
230 | ret = uni_reader_prepare_pcm(runtime, reader); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | |||
176 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 234 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
177 | case SND_SOC_DAIFMT_I2S: | 235 | case SND_SOC_DAIFMT_I2S: |
178 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | 236 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); |
@@ -191,21 +249,26 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, | |||
191 | return -EINVAL; | 249 | return -EINVAL; |
192 | } | 250 | } |
193 | 251 | ||
194 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | 252 | /* Data clocking (changing) on the rising/falling edge */ |
195 | 253 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | |
196 | /* Data clocking (changing) on the rising edge */ | 254 | case SND_SOC_DAIFMT_NB_NF: |
197 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | 255 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); |
198 | 256 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | |
199 | /* Number of channels must be even */ | 257 | break; |
200 | 258 | case SND_SOC_DAIFMT_NB_IF: | |
201 | if ((runtime->channels % 2) || (runtime->channels < 2) || | 259 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); |
202 | (runtime->channels > 10)) { | 260 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); |
203 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | 261 | break; |
204 | return -EINVAL; | 262 | case SND_SOC_DAIFMT_IB_NF: |
263 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
264 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader); | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_IB_IF: | ||
267 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
268 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader); | ||
269 | break; | ||
205 | } | 270 | } |
206 | 271 | ||
207 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
208 | |||
209 | /* Clear any pending interrupts */ | 272 | /* Clear any pending interrupts */ |
210 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); | 273 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); |
211 | 274 | ||
@@ -293,6 +356,32 @@ static int uni_reader_trigger(struct snd_pcm_substream *substream, | |||
293 | } | 356 | } |
294 | } | 357 | } |
295 | 358 | ||
359 | static int uni_reader_startup(struct snd_pcm_substream *substream, | ||
360 | struct snd_soc_dai *dai) | ||
361 | { | ||
362 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
363 | struct uniperif *reader = priv->dai_data.uni; | ||
364 | int ret; | ||
365 | |||
366 | if (!UNIPERIF_TYPE_IS_TDM(reader)) | ||
367 | return 0; | ||
368 | |||
369 | /* refine hw constraint in tdm mode */ | ||
370 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
371 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
372 | sti_uniperiph_fix_tdm_chan, | ||
373 | reader, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
374 | -1); | ||
375 | if (ret < 0) | ||
376 | return ret; | ||
377 | |||
378 | return snd_pcm_hw_rule_add(substream->runtime, 0, | ||
379 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
380 | sti_uniperiph_fix_tdm_format, | ||
381 | reader, SNDRV_PCM_HW_PARAM_FORMAT, | ||
382 | -1); | ||
383 | } | ||
384 | |||
296 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, | 385 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, |
297 | struct snd_soc_dai *dai) | 386 | struct snd_soc_dai *dai) |
298 | { | 387 | { |
@@ -310,6 +399,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
310 | { | 399 | { |
311 | struct uniperif_info *info; | 400 | struct uniperif_info *info; |
312 | struct device_node *node = pdev->dev.of_node; | 401 | struct device_node *node = pdev->dev.of_node; |
402 | const char *mode; | ||
313 | 403 | ||
314 | /* Allocate memory for the info structure */ | 404 | /* Allocate memory for the info structure */ |
315 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 405 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
@@ -322,6 +412,17 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
322 | return -EINVAL; | 412 | return -EINVAL; |
323 | } | 413 | } |
324 | 414 | ||
415 | /* Read the device mode property */ | ||
416 | if (of_property_read_string(node, "st,mode", &mode)) { | ||
417 | dev_err(&pdev->dev, "uniperipheral mode not defined"); | ||
418 | return -EINVAL; | ||
419 | } | ||
420 | |||
421 | if (strcasecmp(mode, "tdm") == 0) | ||
422 | info->type = SND_ST_UNIPERIF_TYPE_TDM; | ||
423 | else | ||
424 | info->type = SND_ST_UNIPERIF_TYPE_PCM; | ||
425 | |||
325 | /* Save the info structure */ | 426 | /* Save the info structure */ |
326 | reader->info = info; | 427 | reader->info = info; |
327 | 428 | ||
@@ -329,11 +430,13 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
329 | } | 430 | } |
330 | 431 | ||
331 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { | 432 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { |
433 | .startup = uni_reader_startup, | ||
332 | .shutdown = uni_reader_shutdown, | 434 | .shutdown = uni_reader_shutdown, |
333 | .prepare = uni_reader_prepare, | 435 | .prepare = uni_reader_prepare, |
334 | .trigger = uni_reader_trigger, | 436 | .trigger = uni_reader_trigger, |
335 | .hw_params = sti_uniperiph_dai_hw_params, | 437 | .hw_params = sti_uniperiph_dai_hw_params, |
336 | .set_fmt = sti_uniperiph_dai_set_fmt, | 438 | .set_fmt = sti_uniperiph_dai_set_fmt, |
439 | .set_tdm_slot = sti_uniperiph_set_tdm_slot | ||
337 | }; | 440 | }; |
338 | 441 | ||
339 | int uni_reader_init(struct platform_device *pdev, | 442 | int uni_reader_init(struct platform_device *pdev, |
@@ -343,7 +446,6 @@ int uni_reader_init(struct platform_device *pdev, | |||
343 | 446 | ||
344 | reader->dev = &pdev->dev; | 447 | reader->dev = &pdev->dev; |
345 | reader->state = UNIPERIF_STATE_STOPPED; | 448 | reader->state = UNIPERIF_STATE_STOPPED; |
346 | reader->hw = &uni_reader_pcm_hw; | ||
347 | reader->dai_ops = &uni_reader_dai_ops; | 449 | reader->dai_ops = &uni_reader_dai_ops; |
348 | 450 | ||
349 | ret = uni_reader_parse_dt(pdev, reader); | 451 | ret = uni_reader_parse_dt(pdev, reader); |
@@ -352,6 +454,11 @@ int uni_reader_init(struct platform_device *pdev, | |||
352 | return ret; | 454 | return ret; |
353 | } | 455 | } |
354 | 456 | ||
457 | if (UNIPERIF_TYPE_IS_TDM(reader)) | ||
458 | reader->hw = &uni_tdm_hw; | ||
459 | else | ||
460 | reader->hw = &uni_reader_pcm_hw; | ||
461 | |||
355 | ret = devm_request_irq(&pdev->dev, reader->irq, | 462 | ret = devm_request_irq(&pdev->dev, reader->irq, |
356 | uni_reader_irq_handler, IRQF_SHARED, | 463 | uni_reader_irq_handler, IRQF_SHARED, |
357 | dev_name(&pdev->dev), reader); | 464 | dev_name(&pdev->dev), reader); |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index d14bf411515b..a452ad7cec40 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -15,7 +15,6 @@ config SND_USB_AUDIO | |||
15 | select SND_RAWMIDI | 15 | select SND_RAWMIDI |
16 | select SND_PCM | 16 | select SND_PCM |
17 | select BITREVERSE | 17 | select BITREVERSE |
18 | select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO) | ||
19 | help | 18 | help |
20 | Say Y here to include support for USB audio and USB MIDI | 19 | Say Y here to include support for USB audio and USB MIDI |
21 | devices. | 20 | devices. |
@@ -23,9 +22,6 @@ config SND_USB_AUDIO | |||
23 | To compile this driver as a module, choose M here: the module | 22 | To compile this driver as a module, choose M here: the module |
24 | will be called snd-usb-audio. | 23 | will be called snd-usb-audio. |
25 | 24 | ||
26 | config SND_USB_AUDIO_USE_MEDIA_CONTROLLER | ||
27 | bool | ||
28 | |||
29 | config SND_USB_UA101 | 25 | config SND_USB_UA101 |
30 | tristate "Edirol UA-101/UA-1000 driver" | 26 | tristate "Edirol UA-101/UA-1000 driver" |
31 | select SND_PCM | 27 | select SND_PCM |
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index 8dca3c407f5a..2d2d122b069f 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
@@ -15,8 +15,6 @@ snd-usb-audio-objs := card.o \ | |||
15 | quirks.o \ | 15 | quirks.o \ |
16 | stream.o | 16 | stream.o |
17 | 17 | ||
18 | snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o | ||
19 | |||
20 | snd-usbmidi-lib-objs := midi.o | 18 | snd-usbmidi-lib-objs := midi.o |
21 | 19 | ||
22 | # Toplevel Module Dependency | 20 | # Toplevel Module Dependency |
diff --git a/sound/usb/card.c b/sound/usb/card.c index 63244bbba8c7..3fc63583a537 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -66,7 +66,6 @@ | |||
66 | #include "format.h" | 66 | #include "format.h" |
67 | #include "power.h" | 67 | #include "power.h" |
68 | #include "stream.h" | 68 | #include "stream.h" |
69 | #include "media.h" | ||
70 | 69 | ||
71 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); | 70 | MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); |
72 | MODULE_DESCRIPTION("USB Audio"); | 71 | MODULE_DESCRIPTION("USB Audio"); |
@@ -612,11 +611,6 @@ static int usb_audio_probe(struct usb_interface *intf, | |||
612 | if (err < 0) | 611 | if (err < 0) |
613 | goto __error; | 612 | goto __error; |
614 | 613 | ||
615 | if (quirk->media_device) { | ||
616 | /* don't want to fail when media_snd_device_create() fails */ | ||
617 | media_snd_device_create(chip, intf); | ||
618 | } | ||
619 | |||
620 | usb_chip[chip->index] = chip; | 614 | usb_chip[chip->index] = chip; |
621 | chip->num_interfaces++; | 615 | chip->num_interfaces++; |
622 | usb_set_intfdata(intf, chip); | 616 | usb_set_intfdata(intf, chip); |
@@ -673,14 +667,6 @@ static void usb_audio_disconnect(struct usb_interface *intf) | |||
673 | list_for_each(p, &chip->midi_list) { | 667 | list_for_each(p, &chip->midi_list) { |
674 | snd_usbmidi_disconnect(p); | 668 | snd_usbmidi_disconnect(p); |
675 | } | 669 | } |
676 | /* | ||
677 | * Nice to check quirk && quirk->media_device | ||
678 | * need some special handlings. Doesn't look like | ||
679 | * we have access to quirk here | ||
680 | * Acceses mixer_list | ||
681 | */ | ||
682 | media_snd_device_delete(chip); | ||
683 | |||
684 | /* release mixer resources */ | 670 | /* release mixer resources */ |
685 | list_for_each_entry(mixer, &chip->mixer_list, list) { | 671 | list_for_each_entry(mixer, &chip->mixer_list, list) { |
686 | snd_usb_mixer_disconnect(mixer); | 672 | snd_usb_mixer_disconnect(mixer); |
diff --git a/sound/usb/card.h b/sound/usb/card.h index 34a0898e2238..71778ca4b26a 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
@@ -105,8 +105,6 @@ struct snd_usb_endpoint { | |||
105 | struct list_head list; | 105 | struct list_head list; |
106 | }; | 106 | }; |
107 | 107 | ||
108 | struct media_ctl; | ||
109 | |||
110 | struct snd_usb_substream { | 108 | struct snd_usb_substream { |
111 | struct snd_usb_stream *stream; | 109 | struct snd_usb_stream *stream; |
112 | struct usb_device *dev; | 110 | struct usb_device *dev; |
@@ -158,7 +156,6 @@ struct snd_usb_substream { | |||
158 | } dsd_dop; | 156 | } dsd_dop; |
159 | 157 | ||
160 | bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ | 158 | bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ |
161 | struct media_ctl *media_ctl; | ||
162 | }; | 159 | }; |
163 | 160 | ||
164 | struct snd_usb_stream { | 161 | struct snd_usb_stream { |
diff --git a/sound/usb/media.c b/sound/usb/media.c deleted file mode 100644 index 93a50d01490c..000000000000 --- a/sound/usb/media.c +++ /dev/null | |||
@@ -1,318 +0,0 @@ | |||
1 | /* | ||
2 | * media.c - Media Controller specific ALSA driver code | ||
3 | * | ||
4 | * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com> | ||
5 | * Copyright (c) 2016 Samsung Electronics Co., Ltd. | ||
6 | * | ||
7 | * This file is released under the GPLv2. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This file adds Media Controller support to ALSA driver | ||
12 | * to use the Media Controller API to share tuner with DVB | ||
13 | * and V4L2 drivers that control media device. Media device | ||
14 | * is created based on existing quirks framework. Using this | ||
15 | * approach, the media controller API usage can be added for | ||
16 | * a specific device. | ||
17 | */ | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/list.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/usb.h> | ||
24 | |||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/core.h> | ||
27 | |||
28 | #include "usbaudio.h" | ||
29 | #include "card.h" | ||
30 | #include "mixer.h" | ||
31 | #include "media.h" | ||
32 | |||
33 | static int media_snd_enable_source(struct media_ctl *mctl) | ||
34 | { | ||
35 | if (mctl && mctl->media_dev->enable_source) | ||
36 | return mctl->media_dev->enable_source(&mctl->media_entity, | ||
37 | &mctl->media_pipe); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static void media_snd_disable_source(struct media_ctl *mctl) | ||
42 | { | ||
43 | if (mctl && mctl->media_dev->disable_source) | ||
44 | mctl->media_dev->disable_source(&mctl->media_entity); | ||
45 | } | ||
46 | |||
47 | int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, | ||
48 | int stream) | ||
49 | { | ||
50 | struct media_device *mdev; | ||
51 | struct media_ctl *mctl; | ||
52 | struct device *pcm_dev = &pcm->streams[stream].dev; | ||
53 | u32 intf_type; | ||
54 | int ret = 0; | ||
55 | u16 mixer_pad; | ||
56 | struct media_entity *entity; | ||
57 | |||
58 | mdev = subs->stream->chip->media_dev; | ||
59 | if (!mdev) | ||
60 | return -ENODEV; | ||
61 | |||
62 | if (subs->media_ctl) | ||
63 | return 0; | ||
64 | |||
65 | /* allocate media_ctl */ | ||
66 | mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); | ||
67 | if (!mctl) | ||
68 | return -ENOMEM; | ||
69 | |||
70 | mctl->media_dev = mdev; | ||
71 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
72 | intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK; | ||
73 | mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK; | ||
74 | mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE; | ||
75 | mixer_pad = 1; | ||
76 | } else { | ||
77 | intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE; | ||
78 | mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE; | ||
79 | mctl->media_pad.flags = MEDIA_PAD_FL_SINK; | ||
80 | mixer_pad = 2; | ||
81 | } | ||
82 | mctl->media_entity.name = pcm->name; | ||
83 | media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad); | ||
84 | ret = media_device_register_entity(mctl->media_dev, | ||
85 | &mctl->media_entity); | ||
86 | if (ret) | ||
87 | goto free_mctl; | ||
88 | |||
89 | mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0, | ||
90 | MAJOR(pcm_dev->devt), | ||
91 | MINOR(pcm_dev->devt)); | ||
92 | if (!mctl->intf_devnode) { | ||
93 | ret = -ENOMEM; | ||
94 | goto unregister_entity; | ||
95 | } | ||
96 | mctl->intf_link = media_create_intf_link(&mctl->media_entity, | ||
97 | &mctl->intf_devnode->intf, | ||
98 | MEDIA_LNK_FL_ENABLED); | ||
99 | if (!mctl->intf_link) { | ||
100 | ret = -ENOMEM; | ||
101 | goto devnode_remove; | ||
102 | } | ||
103 | |||
104 | /* create link between mixer and audio */ | ||
105 | media_device_for_each_entity(entity, mdev) { | ||
106 | switch (entity->function) { | ||
107 | case MEDIA_ENT_F_AUDIO_MIXER: | ||
108 | ret = media_create_pad_link(entity, mixer_pad, | ||
109 | &mctl->media_entity, 0, | ||
110 | MEDIA_LNK_FL_ENABLED); | ||
111 | if (ret) | ||
112 | goto remove_intf_link; | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | subs->media_ctl = mctl; | ||
118 | return 0; | ||
119 | |||
120 | remove_intf_link: | ||
121 | media_remove_intf_link(mctl->intf_link); | ||
122 | devnode_remove: | ||
123 | media_devnode_remove(mctl->intf_devnode); | ||
124 | unregister_entity: | ||
125 | media_device_unregister_entity(&mctl->media_entity); | ||
126 | free_mctl: | ||
127 | kfree(mctl); | ||
128 | return ret; | ||
129 | } | ||
130 | |||
131 | void media_snd_stream_delete(struct snd_usb_substream *subs) | ||
132 | { | ||
133 | struct media_ctl *mctl = subs->media_ctl; | ||
134 | |||
135 | if (mctl && mctl->media_dev) { | ||
136 | struct media_device *mdev; | ||
137 | |||
138 | mdev = subs->stream->chip->media_dev; | ||
139 | if (mdev && media_devnode_is_registered(&mdev->devnode)) { | ||
140 | media_devnode_remove(mctl->intf_devnode); | ||
141 | media_device_unregister_entity(&mctl->media_entity); | ||
142 | media_entity_cleanup(&mctl->media_entity); | ||
143 | } | ||
144 | kfree(mctl); | ||
145 | subs->media_ctl = NULL; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | int media_snd_start_pipeline(struct snd_usb_substream *subs) | ||
150 | { | ||
151 | struct media_ctl *mctl = subs->media_ctl; | ||
152 | |||
153 | if (mctl) | ||
154 | return media_snd_enable_source(mctl); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | void media_snd_stop_pipeline(struct snd_usb_substream *subs) | ||
159 | { | ||
160 | struct media_ctl *mctl = subs->media_ctl; | ||
161 | |||
162 | if (mctl) | ||
163 | media_snd_disable_source(mctl); | ||
164 | } | ||
165 | |||
166 | int media_snd_mixer_init(struct snd_usb_audio *chip) | ||
167 | { | ||
168 | struct device *ctl_dev = &chip->card->ctl_dev; | ||
169 | struct media_intf_devnode *ctl_intf; | ||
170 | struct usb_mixer_interface *mixer; | ||
171 | struct media_device *mdev = chip->media_dev; | ||
172 | struct media_mixer_ctl *mctl; | ||
173 | u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL; | ||
174 | int ret; | ||
175 | |||
176 | if (!mdev) | ||
177 | return -ENODEV; | ||
178 | |||
179 | ctl_intf = chip->ctl_intf_media_devnode; | ||
180 | if (!ctl_intf) { | ||
181 | ctl_intf = media_devnode_create(mdev, intf_type, 0, | ||
182 | MAJOR(ctl_dev->devt), | ||
183 | MINOR(ctl_dev->devt)); | ||
184 | if (!ctl_intf) | ||
185 | return -ENOMEM; | ||
186 | chip->ctl_intf_media_devnode = ctl_intf; | ||
187 | } | ||
188 | |||
189 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
190 | |||
191 | if (mixer->media_mixer_ctl) | ||
192 | continue; | ||
193 | |||
194 | /* allocate media_mixer_ctl */ | ||
195 | mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); | ||
196 | if (!mctl) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | mctl->media_dev = mdev; | ||
200 | mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER; | ||
201 | mctl->media_entity.name = chip->card->mixername; | ||
202 | mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK; | ||
203 | mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE; | ||
204 | mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE; | ||
205 | media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX, | ||
206 | mctl->media_pad); | ||
207 | ret = media_device_register_entity(mctl->media_dev, | ||
208 | &mctl->media_entity); | ||
209 | if (ret) { | ||
210 | kfree(mctl); | ||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | mctl->intf_link = media_create_intf_link(&mctl->media_entity, | ||
215 | &ctl_intf->intf, | ||
216 | MEDIA_LNK_FL_ENABLED); | ||
217 | if (!mctl->intf_link) { | ||
218 | media_device_unregister_entity(&mctl->media_entity); | ||
219 | media_entity_cleanup(&mctl->media_entity); | ||
220 | kfree(mctl); | ||
221 | return -ENOMEM; | ||
222 | } | ||
223 | mctl->intf_devnode = ctl_intf; | ||
224 | mixer->media_mixer_ctl = mctl; | ||
225 | } | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static void media_snd_mixer_delete(struct snd_usb_audio *chip) | ||
230 | { | ||
231 | struct usb_mixer_interface *mixer; | ||
232 | struct media_device *mdev = chip->media_dev; | ||
233 | |||
234 | if (!mdev) | ||
235 | return; | ||
236 | |||
237 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
238 | struct media_mixer_ctl *mctl; | ||
239 | |||
240 | mctl = mixer->media_mixer_ctl; | ||
241 | if (!mixer->media_mixer_ctl) | ||
242 | continue; | ||
243 | |||
244 | if (media_devnode_is_registered(&mdev->devnode)) { | ||
245 | media_device_unregister_entity(&mctl->media_entity); | ||
246 | media_entity_cleanup(&mctl->media_entity); | ||
247 | } | ||
248 | kfree(mctl); | ||
249 | mixer->media_mixer_ctl = NULL; | ||
250 | } | ||
251 | if (media_devnode_is_registered(&mdev->devnode)) | ||
252 | media_devnode_remove(chip->ctl_intf_media_devnode); | ||
253 | chip->ctl_intf_media_devnode = NULL; | ||
254 | } | ||
255 | |||
256 | int media_snd_device_create(struct snd_usb_audio *chip, | ||
257 | struct usb_interface *iface) | ||
258 | { | ||
259 | struct media_device *mdev; | ||
260 | struct usb_device *usbdev = interface_to_usbdev(iface); | ||
261 | int ret; | ||
262 | |||
263 | mdev = media_device_get_devres(&usbdev->dev); | ||
264 | if (!mdev) | ||
265 | return -ENOMEM; | ||
266 | if (!mdev->dev) { | ||
267 | /* register media device */ | ||
268 | mdev->dev = &usbdev->dev; | ||
269 | if (usbdev->product) | ||
270 | strlcpy(mdev->model, usbdev->product, | ||
271 | sizeof(mdev->model)); | ||
272 | if (usbdev->serial) | ||
273 | strlcpy(mdev->serial, usbdev->serial, | ||
274 | sizeof(mdev->serial)); | ||
275 | strcpy(mdev->bus_info, usbdev->devpath); | ||
276 | mdev->hw_revision = le16_to_cpu(usbdev->descriptor.bcdDevice); | ||
277 | media_device_init(mdev); | ||
278 | } | ||
279 | if (!media_devnode_is_registered(&mdev->devnode)) { | ||
280 | ret = media_device_register(mdev); | ||
281 | if (ret) { | ||
282 | dev_err(&usbdev->dev, | ||
283 | "Couldn't register media device. Error: %d\n", | ||
284 | ret); | ||
285 | return ret; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* save media device - avoid lookups */ | ||
290 | chip->media_dev = mdev; | ||
291 | |||
292 | /* Create media entities for mixer and control dev */ | ||
293 | ret = media_snd_mixer_init(chip); | ||
294 | if (ret) { | ||
295 | dev_err(&usbdev->dev, | ||
296 | "Couldn't create media mixer entities. Error: %d\n", | ||
297 | ret); | ||
298 | |||
299 | /* clear saved media_dev */ | ||
300 | chip->media_dev = NULL; | ||
301 | |||
302 | return ret; | ||
303 | } | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | void media_snd_device_delete(struct snd_usb_audio *chip) | ||
308 | { | ||
309 | struct media_device *mdev = chip->media_dev; | ||
310 | |||
311 | media_snd_mixer_delete(chip); | ||
312 | |||
313 | if (mdev) { | ||
314 | if (media_devnode_is_registered(&mdev->devnode)) | ||
315 | media_device_unregister(mdev); | ||
316 | chip->media_dev = NULL; | ||
317 | } | ||
318 | } | ||
diff --git a/sound/usb/media.h b/sound/usb/media.h deleted file mode 100644 index 1dcdcdc5f7aa..000000000000 --- a/sound/usb/media.h +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | /* | ||
2 | * media.h - Media Controller specific ALSA driver code | ||
3 | * | ||
4 | * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com> | ||
5 | * Copyright (c) 2016 Samsung Electronics Co., Ltd. | ||
6 | * | ||
7 | * This file is released under the GPLv2. | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * This file adds Media Controller support to ALSA driver | ||
12 | * to use the Media Controller API to share tuner with DVB | ||
13 | * and V4L2 drivers that control media device. Media device | ||
14 | * is created based on existing quirks framework. Using this | ||
15 | * approach, the media controller API usage can be added for | ||
16 | * a specific device. | ||
17 | */ | ||
18 | #ifndef __MEDIA_H | ||
19 | |||
20 | #ifdef CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER | ||
21 | |||
22 | #include <media/media-device.h> | ||
23 | #include <media/media-entity.h> | ||
24 | #include <sound/asound.h> | ||
25 | |||
26 | struct media_ctl { | ||
27 | struct media_device *media_dev; | ||
28 | struct media_entity media_entity; | ||
29 | struct media_intf_devnode *intf_devnode; | ||
30 | struct media_link *intf_link; | ||
31 | struct media_pad media_pad; | ||
32 | struct media_pipeline media_pipe; | ||
33 | }; | ||
34 | |||
35 | /* | ||
36 | * One source pad each for SNDRV_PCM_STREAM_CAPTURE and | ||
37 | * SNDRV_PCM_STREAM_PLAYBACK. One for sink pad to link | ||
38 | * to AUDIO Source | ||
39 | */ | ||
40 | #define MEDIA_MIXER_PAD_MAX (SNDRV_PCM_STREAM_LAST + 2) | ||
41 | |||
42 | struct media_mixer_ctl { | ||
43 | struct media_device *media_dev; | ||
44 | struct media_entity media_entity; | ||
45 | struct media_intf_devnode *intf_devnode; | ||
46 | struct media_link *intf_link; | ||
47 | struct media_pad media_pad[MEDIA_MIXER_PAD_MAX]; | ||
48 | struct media_pipeline media_pipe; | ||
49 | }; | ||
50 | |||
51 | int media_snd_device_create(struct snd_usb_audio *chip, | ||
52 | struct usb_interface *iface); | ||
53 | void media_snd_device_delete(struct snd_usb_audio *chip); | ||
54 | int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, | ||
55 | int stream); | ||
56 | void media_snd_stream_delete(struct snd_usb_substream *subs); | ||
57 | int media_snd_start_pipeline(struct snd_usb_substream *subs); | ||
58 | void media_snd_stop_pipeline(struct snd_usb_substream *subs); | ||
59 | #else | ||
60 | static inline int media_snd_device_create(struct snd_usb_audio *chip, | ||
61 | struct usb_interface *iface) | ||
62 | { return 0; } | ||
63 | static inline void media_snd_device_delete(struct snd_usb_audio *chip) { } | ||
64 | static inline int media_snd_stream_init(struct snd_usb_substream *subs, | ||
65 | struct snd_pcm *pcm, int stream) | ||
66 | { return 0; } | ||
67 | static inline void media_snd_stream_delete(struct snd_usb_substream *subs) { } | ||
68 | static inline int media_snd_start_pipeline(struct snd_usb_substream *subs) | ||
69 | { return 0; } | ||
70 | static inline void media_snd_stop_pipeline(struct snd_usb_substream *subs) { } | ||
71 | #endif | ||
72 | #endif /* __MEDIA_H */ | ||
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index f3789446ab9c..3417ef347e40 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -3,8 +3,6 @@ | |||
3 | 3 | ||
4 | #include <sound/info.h> | 4 | #include <sound/info.h> |
5 | 5 | ||
6 | struct media_mixer_ctl; | ||
7 | |||
8 | struct usb_mixer_interface { | 6 | struct usb_mixer_interface { |
9 | struct snd_usb_audio *chip; | 7 | struct snd_usb_audio *chip; |
10 | struct usb_host_interface *hostif; | 8 | struct usb_host_interface *hostif; |
@@ -24,7 +22,6 @@ struct usb_mixer_interface { | |||
24 | struct urb *rc_urb; | 22 | struct urb *rc_urb; |
25 | struct usb_ctrlrequest *rc_setup_packet; | 23 | struct usb_ctrlrequest *rc_setup_packet; |
26 | u8 rc_buffer[6]; | 24 | u8 rc_buffer[6]; |
27 | struct media_mixer_ctl *media_mixer_ctl; | ||
28 | }; | 25 | }; |
29 | 26 | ||
30 | #define MAX_CHANNELS 16 /* max logical channels */ | 27 | #define MAX_CHANNELS 16 /* max logical channels */ |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index ddca6547399b..1f8fb0d904e0 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -349,6 +349,16 @@ static struct usbmix_name_map bose_companion5_map[] = { | |||
349 | }; | 349 | }; |
350 | 350 | ||
351 | /* | 351 | /* |
352 | * Dell usb dock with ALC4020 codec had a firmware problem where it got | ||
353 | * screwed up when zero volume is passed; just skip it as a workaround | ||
354 | */ | ||
355 | static const struct usbmix_name_map dell_alc4020_map[] = { | ||
356 | { 16, NULL }, | ||
357 | { 19, NULL }, | ||
358 | { 0 } | ||
359 | }; | ||
360 | |||
361 | /* | ||
352 | * Control map entries | 362 | * Control map entries |
353 | */ | 363 | */ |
354 | 364 | ||
@@ -431,6 +441,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
431 | .map = aureon_51_2_map, | 441 | .map = aureon_51_2_map, |
432 | }, | 442 | }, |
433 | { | 443 | { |
444 | .id = USB_ID(0x0bda, 0x4014), | ||
445 | .map = dell_alc4020_map, | ||
446 | }, | ||
447 | { | ||
434 | .id = USB_ID(0x0dba, 0x1000), | 448 | .id = USB_ID(0x0dba, 0x1000), |
435 | .map = mbox1_map, | 449 | .map = mbox1_map, |
436 | }, | 450 | }, |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0e4e0640c504..44d178ee9177 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include "pcm.h" | 35 | #include "pcm.h" |
36 | #include "clock.h" | 36 | #include "clock.h" |
37 | #include "power.h" | 37 | #include "power.h" |
38 | #include "media.h" | ||
39 | 38 | ||
40 | #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 | 39 | #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 |
41 | #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 | 40 | #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 |
@@ -718,14 +717,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
718 | struct audioformat *fmt; | 717 | struct audioformat *fmt; |
719 | int ret; | 718 | int ret; |
720 | 719 | ||
721 | ret = media_snd_start_pipeline(subs); | ||
722 | if (ret) | ||
723 | return ret; | ||
724 | |||
725 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, | 720 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
726 | params_buffer_bytes(hw_params)); | 721 | params_buffer_bytes(hw_params)); |
727 | if (ret < 0) | 722 | if (ret < 0) |
728 | goto err_ret; | 723 | return ret; |
729 | 724 | ||
730 | subs->pcm_format = params_format(hw_params); | 725 | subs->pcm_format = params_format(hw_params); |
731 | subs->period_bytes = params_period_bytes(hw_params); | 726 | subs->period_bytes = params_period_bytes(hw_params); |
@@ -739,27 +734,22 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
739 | dev_dbg(&subs->dev->dev, | 734 | dev_dbg(&subs->dev->dev, |
740 | "cannot set format: format = %#x, rate = %d, channels = %d\n", | 735 | "cannot set format: format = %#x, rate = %d, channels = %d\n", |
741 | subs->pcm_format, subs->cur_rate, subs->channels); | 736 | subs->pcm_format, subs->cur_rate, subs->channels); |
742 | ret = -EINVAL; | 737 | return -EINVAL; |
743 | goto err_ret; | ||
744 | } | 738 | } |
745 | 739 | ||
746 | ret = snd_usb_lock_shutdown(subs->stream->chip); | 740 | ret = snd_usb_lock_shutdown(subs->stream->chip); |
747 | if (ret < 0) | 741 | if (ret < 0) |
748 | goto err_ret; | 742 | return ret; |
749 | ret = set_format(subs, fmt); | 743 | ret = set_format(subs, fmt); |
750 | snd_usb_unlock_shutdown(subs->stream->chip); | 744 | snd_usb_unlock_shutdown(subs->stream->chip); |
751 | if (ret < 0) | 745 | if (ret < 0) |
752 | goto err_ret; | 746 | return ret; |
753 | 747 | ||
754 | subs->interface = fmt->iface; | 748 | subs->interface = fmt->iface; |
755 | subs->altset_idx = fmt->altset_idx; | 749 | subs->altset_idx = fmt->altset_idx; |
756 | subs->need_setup_ep = true; | 750 | subs->need_setup_ep = true; |
757 | 751 | ||
758 | return 0; | 752 | return 0; |
759 | |||
760 | err_ret: | ||
761 | media_snd_stop_pipeline(subs); | ||
762 | return ret; | ||
763 | } | 753 | } |
764 | 754 | ||
765 | /* | 755 | /* |
@@ -771,7 +761,6 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
771 | { | 761 | { |
772 | struct snd_usb_substream *subs = substream->runtime->private_data; | 762 | struct snd_usb_substream *subs = substream->runtime->private_data; |
773 | 763 | ||
774 | media_snd_stop_pipeline(subs); | ||
775 | subs->cur_audiofmt = NULL; | 764 | subs->cur_audiofmt = NULL; |
776 | subs->cur_rate = 0; | 765 | subs->cur_rate = 0; |
777 | subs->period_bytes = 0; | 766 | subs->period_bytes = 0; |
@@ -1232,7 +1221,6 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
1232 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); | 1221 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); |
1233 | struct snd_pcm_runtime *runtime = substream->runtime; | 1222 | struct snd_pcm_runtime *runtime = substream->runtime; |
1234 | struct snd_usb_substream *subs = &as->substream[direction]; | 1223 | struct snd_usb_substream *subs = &as->substream[direction]; |
1235 | int ret; | ||
1236 | 1224 | ||
1237 | subs->interface = -1; | 1225 | subs->interface = -1; |
1238 | subs->altset_idx = 0; | 1226 | subs->altset_idx = 0; |
@@ -1246,12 +1234,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
1246 | subs->dsd_dop.channel = 0; | 1234 | subs->dsd_dop.channel = 0; |
1247 | subs->dsd_dop.marker = 1; | 1235 | subs->dsd_dop.marker = 1; |
1248 | 1236 | ||
1249 | ret = setup_hw_info(runtime, subs); | 1237 | return setup_hw_info(runtime, subs); |
1250 | if (ret == 0) | ||
1251 | ret = media_snd_stream_init(subs, as->pcm, direction); | ||
1252 | if (ret) | ||
1253 | snd_usb_autosuspend(subs->stream->chip); | ||
1254 | return ret; | ||
1255 | } | 1238 | } |
1256 | 1239 | ||
1257 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | 1240 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) |
@@ -1260,7 +1243,6 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | |||
1260 | struct snd_usb_substream *subs = &as->substream[direction]; | 1243 | struct snd_usb_substream *subs = &as->substream[direction]; |
1261 | 1244 | ||
1262 | stop_endpoints(subs, true); | 1245 | stop_endpoints(subs, true); |
1263 | media_snd_stop_pipeline(subs); | ||
1264 | 1246 | ||
1265 | if (subs->interface >= 0 && | 1247 | if (subs->interface >= 0 && |
1266 | !snd_usb_lock_shutdown(subs->stream->chip)) { | 1248 | !snd_usb_lock_shutdown(subs->stream->chip)) { |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 9d087b19c70c..c60a776e815d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -2886,7 +2886,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2886 | .product_name = pname, \ | 2886 | .product_name = pname, \ |
2887 | .ifnum = QUIRK_ANY_INTERFACE, \ | 2887 | .ifnum = QUIRK_ANY_INTERFACE, \ |
2888 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, \ | 2888 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, \ |
2889 | .media_device = 1, \ | ||
2890 | } \ | 2889 | } \ |
2891 | } | 2890 | } |
2892 | 2891 | ||
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index fb62bce2435c..6adde457b602 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -150,6 +150,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, | |||
150 | usb_audio_err(chip, "cannot memdup\n"); | 150 | usb_audio_err(chip, "cannot memdup\n"); |
151 | return -ENOMEM; | 151 | return -ENOMEM; |
152 | } | 152 | } |
153 | INIT_LIST_HEAD(&fp->list); | ||
153 | if (fp->nr_rates > MAX_NR_RATES) { | 154 | if (fp->nr_rates > MAX_NR_RATES) { |
154 | kfree(fp); | 155 | kfree(fp); |
155 | return -EINVAL; | 156 | return -EINVAL; |
@@ -193,6 +194,7 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip, | |||
193 | return 0; | 194 | return 0; |
194 | 195 | ||
195 | error: | 196 | error: |
197 | list_del(&fp->list); /* unlink for avoiding double-free */ | ||
196 | kfree(fp); | 198 | kfree(fp); |
197 | kfree(rate_table); | 199 | kfree(rate_table); |
198 | return err; | 200 | return err; |
@@ -469,6 +471,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, | |||
469 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | 471 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; |
470 | fp->datainterval = 0; | 472 | fp->datainterval = 0; |
471 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | 473 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); |
474 | INIT_LIST_HEAD(&fp->list); | ||
472 | 475 | ||
473 | switch (fp->maxpacksize) { | 476 | switch (fp->maxpacksize) { |
474 | case 0x120: | 477 | case 0x120: |
@@ -492,6 +495,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, | |||
492 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | 495 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; |
493 | err = snd_usb_add_audio_stream(chip, stream, fp); | 496 | err = snd_usb_add_audio_stream(chip, stream, fp); |
494 | if (err < 0) { | 497 | if (err < 0) { |
498 | list_del(&fp->list); /* unlink for avoiding double-free */ | ||
495 | kfree(fp); | 499 | kfree(fp); |
496 | return err; | 500 | return err; |
497 | } | 501 | } |
@@ -1130,9 +1134,14 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip) | |||
1130 | case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ | 1134 | case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */ |
1131 | case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ | 1135 | case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */ |
1132 | case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ | 1136 | case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */ |
1137 | case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */ | ||
1133 | case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ | 1138 | case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */ |
1134 | case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ | 1139 | case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */ |
1140 | case USB_ID(0x0556, 0x0014): /* Phoenix Audio TMX320VC */ | ||
1135 | case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ | 1141 | case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */ |
1142 | case USB_ID(0x1de7, 0x0013): /* Phoenix Audio MT202exe */ | ||
1143 | case USB_ID(0x1de7, 0x0014): /* Phoenix Audio TMX320 */ | ||
1144 | case USB_ID(0x1de7, 0x0114): /* Phoenix Audio MT202pcs */ | ||
1136 | case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ | 1145 | case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */ |
1137 | return true; | 1146 | return true; |
1138 | } | 1147 | } |
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 51258a15f653..8e9548bc1f1a 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include "format.h" | 36 | #include "format.h" |
37 | #include "clock.h" | 37 | #include "clock.h" |
38 | #include "stream.h" | 38 | #include "stream.h" |
39 | #include "media.h" | ||
40 | 39 | ||
41 | /* | 40 | /* |
42 | * free a substream | 41 | * free a substream |
@@ -53,7 +52,6 @@ static void free_substream(struct snd_usb_substream *subs) | |||
53 | kfree(fp); | 52 | kfree(fp); |
54 | } | 53 | } |
55 | kfree(subs->rate_list.list); | 54 | kfree(subs->rate_list.list); |
56 | media_snd_stream_delete(subs); | ||
57 | } | 55 | } |
58 | 56 | ||
59 | 57 | ||
@@ -316,7 +314,9 @@ static struct snd_pcm_chmap_elem *convert_chmap(int channels, unsigned int bits, | |||
316 | /* | 314 | /* |
317 | * add this endpoint to the chip instance. | 315 | * add this endpoint to the chip instance. |
318 | * if a stream with the same endpoint already exists, append to it. | 316 | * if a stream with the same endpoint already exists, append to it. |
319 | * if not, create a new pcm stream. | 317 | * if not, create a new pcm stream. note, fp is added to the substream |
318 | * fmt_list and will be freed on the chip instance release. do not free | ||
319 | * fp or do remove it from the substream fmt_list to avoid double-free. | ||
320 | */ | 320 | */ |
321 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, | 321 | int snd_usb_add_audio_stream(struct snd_usb_audio *chip, |
322 | int stream, | 322 | int stream, |
@@ -677,6 +677,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) | |||
677 | * (fp->maxpacksize & 0x7ff); | 677 | * (fp->maxpacksize & 0x7ff); |
678 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); | 678 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); |
679 | fp->clock = clock; | 679 | fp->clock = clock; |
680 | INIT_LIST_HEAD(&fp->list); | ||
680 | 681 | ||
681 | /* some quirks for attributes here */ | 682 | /* some quirks for attributes here */ |
682 | 683 | ||
@@ -725,6 +726,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) | |||
725 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); | 726 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); |
726 | err = snd_usb_add_audio_stream(chip, stream, fp); | 727 | err = snd_usb_add_audio_stream(chip, stream, fp); |
727 | if (err < 0) { | 728 | if (err < 0) { |
729 | list_del(&fp->list); /* unlink for avoiding double-free */ | ||
728 | kfree(fp->rate_table); | 730 | kfree(fp->rate_table); |
729 | kfree(fp->chmap); | 731 | kfree(fp->chmap); |
730 | kfree(fp); | 732 | kfree(fp); |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index a161c7c1b126..b665d85555cb 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -30,9 +30,6 @@ | |||
30 | * | 30 | * |
31 | */ | 31 | */ |
32 | 32 | ||
33 | struct media_device; | ||
34 | struct media_intf_devnode; | ||
35 | |||
36 | struct snd_usb_audio { | 33 | struct snd_usb_audio { |
37 | int index; | 34 | int index; |
38 | struct usb_device *dev; | 35 | struct usb_device *dev; |
@@ -63,8 +60,6 @@ struct snd_usb_audio { | |||
63 | bool autoclock; /* from the 'autoclock' module param */ | 60 | bool autoclock; /* from the 'autoclock' module param */ |
64 | 61 | ||
65 | struct usb_host_interface *ctrl_intf; /* the audio control interface */ | 62 | struct usb_host_interface *ctrl_intf; /* the audio control interface */ |
66 | struct media_device *media_dev; | ||
67 | struct media_intf_devnode *ctl_intf_media_devnode; | ||
68 | }; | 63 | }; |
69 | 64 | ||
70 | #define usb_audio_err(chip, fmt, args...) \ | 65 | #define usb_audio_err(chip, fmt, args...) \ |
@@ -115,7 +110,6 @@ struct snd_usb_audio_quirk { | |||
115 | const char *product_name; | 110 | const char *product_name; |
116 | int16_t ifnum; | 111 | int16_t ifnum; |
117 | uint16_t type; | 112 | uint16_t type; |
118 | bool media_device; | ||
119 | const void *data; | 113 | const void *data; |
120 | }; | 114 | }; |
121 | 115 | ||