diff options
95 files changed, 7805 insertions, 2064 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 29801f760b6f..7bcc3951189f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -533,6 +533,8 @@ L: device-drivers-devel@blackfin.uclinux.org | |||
533 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 533 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
534 | W: http://wiki.analog.com/ | 534 | W: http://wiki.analog.com/ |
535 | S: Supported | 535 | S: Supported |
536 | F: sound/soc/codecs/adau* | ||
537 | F: sound/soc/codecs/adav* | ||
536 | F: sound/soc/codecs/ad1* | 538 | F: sound/soc/codecs/ad1* |
537 | F: sound/soc/codecs/ssm* | 539 | F: sound/soc/codecs/ssm* |
538 | 540 | ||
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 1bafe95dcf41..5ad5f3a50c68 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h | |||
@@ -209,6 +209,10 @@ struct snd_soc_dai_driver { | |||
209 | struct snd_soc_pcm_stream capture; | 209 | struct snd_soc_pcm_stream capture; |
210 | struct snd_soc_pcm_stream playback; | 210 | struct snd_soc_pcm_stream playback; |
211 | unsigned int symmetric_rates:1; | 211 | unsigned int symmetric_rates:1; |
212 | |||
213 | /* probe ordering - for components with runtime dependencies */ | ||
214 | int probe_order; | ||
215 | int remove_order; | ||
212 | }; | 216 | }; |
213 | 217 | ||
214 | /* | 218 | /* |
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index c46e7d89561d..e09505c5a490 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -348,6 +348,8 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm); | |||
348 | void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); | 348 | void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm); |
349 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, | 349 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, |
350 | const struct snd_soc_dapm_route *route, int num); | 350 | const struct snd_soc_dapm_route *route, int num); |
351 | int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, | ||
352 | const struct snd_soc_dapm_route *route, int num); | ||
351 | 353 | ||
352 | /* dapm events */ | 354 | /* dapm events */ |
353 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, | 355 | int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, |
@@ -429,6 +431,7 @@ struct snd_soc_dapm_path { | |||
429 | /* status */ | 431 | /* status */ |
430 | u32 connect:1; /* source and sink widgets are connected */ | 432 | u32 connect:1; /* source and sink widgets are connected */ |
431 | u32 walked:1; /* path has been walked */ | 433 | u32 walked:1; /* path has been walked */ |
434 | u32 weak:1; /* path ignored for power management */ | ||
432 | 435 | ||
433 | int (*connected)(struct snd_soc_dapm_widget *source, | 436 | int (*connected)(struct snd_soc_dapm_widget *source, |
434 | struct snd_soc_dapm_widget *sink); | 437 | struct snd_soc_dapm_widget *sink); |
@@ -444,6 +447,7 @@ struct snd_soc_dapm_widget { | |||
444 | char *name; /* widget name */ | 447 | char *name; /* widget name */ |
445 | char *sname; /* stream name */ | 448 | char *sname; /* stream name */ |
446 | struct snd_soc_codec *codec; | 449 | struct snd_soc_codec *codec; |
450 | struct snd_soc_platform *platform; | ||
447 | struct list_head list; | 451 | struct list_head list; |
448 | struct snd_soc_dapm_context *dapm; | 452 | struct snd_soc_dapm_context *dapm; |
449 | 453 | ||
@@ -507,10 +511,11 @@ struct snd_soc_dapm_context { | |||
507 | 511 | ||
508 | struct device *dev; /* from parent - for debug */ | 512 | struct device *dev; /* from parent - for debug */ |
509 | struct snd_soc_codec *codec; /* parent codec */ | 513 | struct snd_soc_codec *codec; /* parent codec */ |
514 | struct snd_soc_platform *platform; /* parent platform */ | ||
510 | struct snd_soc_card *card; /* parent card */ | 515 | struct snd_soc_card *card; /* parent card */ |
511 | 516 | ||
512 | /* used during DAPM updates */ | 517 | /* used during DAPM updates */ |
513 | int dev_power; | 518 | enum snd_soc_bias_level target_bias_level; |
514 | struct list_head list; | 519 | struct list_head list; |
515 | 520 | ||
516 | #ifdef CONFIG_DEBUG_FS | 521 | #ifdef CONFIG_DEBUG_FS |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 3a4bd3a3c68d..aa19f5a32ba8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -203,6 +203,16 @@ | |||
203 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) | 203 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) |
204 | 204 | ||
205 | /* | 205 | /* |
206 | * Component probe and remove ordering levels for components with runtime | ||
207 | * dependencies. | ||
208 | */ | ||
209 | #define SND_SOC_COMP_ORDER_FIRST -2 | ||
210 | #define SND_SOC_COMP_ORDER_EARLY -1 | ||
211 | #define SND_SOC_COMP_ORDER_NORMAL 0 | ||
212 | #define SND_SOC_COMP_ORDER_LATE 1 | ||
213 | #define SND_SOC_COMP_ORDER_LAST 2 | ||
214 | |||
215 | /* | ||
206 | * Bias levels | 216 | * Bias levels |
207 | * | 217 | * |
208 | * @ON: Bias is fully on for audio playback and capture operations. | 218 | * @ON: Bias is fully on for audio playback and capture operations. |
@@ -214,10 +224,10 @@ | |||
214 | * @OFF: Power Off. No restrictions on transition times. | 224 | * @OFF: Power Off. No restrictions on transition times. |
215 | */ | 225 | */ |
216 | enum snd_soc_bias_level { | 226 | enum snd_soc_bias_level { |
217 | SND_SOC_BIAS_OFF, | 227 | SND_SOC_BIAS_OFF = 0, |
218 | SND_SOC_BIAS_STANDBY, | 228 | SND_SOC_BIAS_STANDBY = 1, |
219 | SND_SOC_BIAS_PREPARE, | 229 | SND_SOC_BIAS_PREPARE = 2, |
220 | SND_SOC_BIAS_ON, | 230 | SND_SOC_BIAS_ON = 3, |
221 | }; | 231 | }; |
222 | 232 | ||
223 | struct snd_jack; | 233 | struct snd_jack; |
@@ -258,6 +268,11 @@ enum snd_soc_compress_type { | |||
258 | SND_SOC_RBTREE_COMPRESSION | 268 | SND_SOC_RBTREE_COMPRESSION |
259 | }; | 269 | }; |
260 | 270 | ||
271 | enum snd_soc_pcm_subclass { | ||
272 | SND_SOC_PCM_CLASS_PCM = 0, | ||
273 | SND_SOC_PCM_CLASS_BE = 1, | ||
274 | }; | ||
275 | |||
261 | int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, | 276 | int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, |
262 | unsigned int freq, int dir); | 277 | unsigned int freq, int dir); |
263 | int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, | 278 | int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, |
@@ -297,6 +312,10 @@ int snd_soc_default_readable_register(struct snd_soc_codec *codec, | |||
297 | unsigned int reg); | 312 | unsigned int reg); |
298 | int snd_soc_default_writable_register(struct snd_soc_codec *codec, | 313 | int snd_soc_default_writable_register(struct snd_soc_codec *codec, |
299 | unsigned int reg); | 314 | unsigned int reg); |
315 | int snd_soc_platform_read(struct snd_soc_platform *platform, | ||
316 | unsigned int reg); | ||
317 | int snd_soc_platform_write(struct snd_soc_platform *platform, | ||
318 | unsigned int reg, unsigned int val); | ||
300 | 319 | ||
301 | /* Utility functions to get clock rates from various things */ | 320 | /* Utility functions to get clock rates from various things */ |
302 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); | 321 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); |
@@ -349,6 +368,8 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | |||
349 | const char *prefix); | 368 | const char *prefix); |
350 | int snd_soc_add_controls(struct snd_soc_codec *codec, | 369 | int snd_soc_add_controls(struct snd_soc_codec *codec, |
351 | const struct snd_kcontrol_new *controls, int num_controls); | 370 | const struct snd_kcontrol_new *controls, int num_controls); |
371 | int snd_soc_add_platform_controls(struct snd_soc_platform *platform, | ||
372 | const struct snd_kcontrol_new *controls, int num_controls); | ||
352 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | 373 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, |
353 | struct snd_ctl_elem_info *uinfo); | 374 | struct snd_ctl_elem_info *uinfo); |
354 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, | 375 | int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol, |
@@ -612,6 +633,10 @@ struct snd_soc_codec_driver { | |||
612 | 633 | ||
613 | void (*seq_notifier)(struct snd_soc_dapm_context *, | 634 | void (*seq_notifier)(struct snd_soc_dapm_context *, |
614 | enum snd_soc_dapm_type, int); | 635 | enum snd_soc_dapm_type, int); |
636 | |||
637 | /* probe ordering - for components with runtime dependencies */ | ||
638 | int probe_order; | ||
639 | int remove_order; | ||
615 | }; | 640 | }; |
616 | 641 | ||
617 | /* SoC platform interface */ | 642 | /* SoC platform interface */ |
@@ -623,10 +648,17 @@ struct snd_soc_platform_driver { | |||
623 | int (*resume)(struct snd_soc_dai *dai); | 648 | int (*resume)(struct snd_soc_dai *dai); |
624 | 649 | ||
625 | /* pcm creation and destruction */ | 650 | /* pcm creation and destruction */ |
626 | int (*pcm_new)(struct snd_card *, struct snd_soc_dai *, | 651 | int (*pcm_new)(struct snd_soc_pcm_runtime *); |
627 | struct snd_pcm *); | ||
628 | void (*pcm_free)(struct snd_pcm *); | 652 | void (*pcm_free)(struct snd_pcm *); |
629 | 653 | ||
654 | /* Default control and setup, added after probe() is run */ | ||
655 | const struct snd_kcontrol_new *controls; | ||
656 | int num_controls; | ||
657 | const struct snd_soc_dapm_widget *dapm_widgets; | ||
658 | int num_dapm_widgets; | ||
659 | const struct snd_soc_dapm_route *dapm_routes; | ||
660 | int num_dapm_routes; | ||
661 | |||
630 | /* | 662 | /* |
631 | * For platform caused delay reporting. | 663 | * For platform caused delay reporting. |
632 | * Optional. | 664 | * Optional. |
@@ -636,6 +668,14 @@ struct snd_soc_platform_driver { | |||
636 | 668 | ||
637 | /* platform stream ops */ | 669 | /* platform stream ops */ |
638 | struct snd_pcm_ops *ops; | 670 | struct snd_pcm_ops *ops; |
671 | |||
672 | /* probe ordering - for components with runtime dependencies */ | ||
673 | int probe_order; | ||
674 | int remove_order; | ||
675 | |||
676 | /* platform IO - used for platform DAPM */ | ||
677 | unsigned int (*read)(struct snd_soc_platform *, unsigned int); | ||
678 | int (*write)(struct snd_soc_platform *, unsigned int, unsigned int); | ||
639 | }; | 679 | }; |
640 | 680 | ||
641 | struct snd_soc_platform { | 681 | struct snd_soc_platform { |
@@ -650,6 +690,8 @@ struct snd_soc_platform { | |||
650 | struct snd_soc_card *card; | 690 | struct snd_soc_card *card; |
651 | struct list_head list; | 691 | struct list_head list; |
652 | struct list_head card_list; | 692 | struct list_head card_list; |
693 | |||
694 | struct snd_soc_dapm_context dapm; | ||
653 | }; | 695 | }; |
654 | 696 | ||
655 | struct snd_soc_dai_link { | 697 | struct snd_soc_dai_link { |
@@ -725,8 +767,10 @@ struct snd_soc_card { | |||
725 | 767 | ||
726 | /* callbacks */ | 768 | /* callbacks */ |
727 | int (*set_bias_level)(struct snd_soc_card *, | 769 | int (*set_bias_level)(struct snd_soc_card *, |
770 | struct snd_soc_dapm_context *dapm, | ||
728 | enum snd_soc_bias_level level); | 771 | enum snd_soc_bias_level level); |
729 | int (*set_bias_level_post)(struct snd_soc_card *, | 772 | int (*set_bias_level_post)(struct snd_soc_card *, |
773 | struct snd_soc_dapm_context *dapm, | ||
730 | enum snd_soc_bias_level level); | 774 | enum snd_soc_bias_level level); |
731 | 775 | ||
732 | long pmdown_time; | 776 | long pmdown_time; |
@@ -789,6 +833,9 @@ struct snd_soc_pcm_runtime { | |||
789 | struct device dev; | 833 | struct device dev; |
790 | struct snd_soc_card *card; | 834 | struct snd_soc_card *card; |
791 | struct snd_soc_dai_link *dai_link; | 835 | struct snd_soc_dai_link *dai_link; |
836 | struct mutex pcm_mutex; | ||
837 | enum snd_soc_pcm_subclass pcm_subclass; | ||
838 | struct snd_pcm_ops ops; | ||
792 | 839 | ||
793 | unsigned int complete:1; | 840 | unsigned int complete:1; |
794 | unsigned int dev_registered:1; | 841 | unsigned int dev_registered:1; |
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index ae973d2e27a1..603f5a0f0365 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | struct snd_soc_jack; | 10 | struct snd_soc_jack; |
11 | struct snd_soc_codec; | 11 | struct snd_soc_codec; |
12 | struct snd_soc_platform; | ||
12 | struct snd_soc_card; | 13 | struct snd_soc_card; |
13 | struct snd_soc_dapm_widget; | 14 | struct snd_soc_dapm_widget; |
14 | 15 | ||
@@ -59,6 +60,50 @@ DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read, | |||
59 | 60 | ||
60 | ); | 61 | ); |
61 | 62 | ||
63 | DECLARE_EVENT_CLASS(snd_soc_preg, | ||
64 | |||
65 | TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, | ||
66 | unsigned int val), | ||
67 | |||
68 | TP_ARGS(platform, reg, val), | ||
69 | |||
70 | TP_STRUCT__entry( | ||
71 | __string( name, platform->name ) | ||
72 | __field( int, id ) | ||
73 | __field( unsigned int, reg ) | ||
74 | __field( unsigned int, val ) | ||
75 | ), | ||
76 | |||
77 | TP_fast_assign( | ||
78 | __assign_str(name, platform->name); | ||
79 | __entry->id = platform->id; | ||
80 | __entry->reg = reg; | ||
81 | __entry->val = val; | ||
82 | ), | ||
83 | |||
84 | TP_printk("platform=%s.%d reg=%x val=%x", __get_str(name), | ||
85 | (int)__entry->id, (unsigned int)__entry->reg, | ||
86 | (unsigned int)__entry->val) | ||
87 | ); | ||
88 | |||
89 | DEFINE_EVENT(snd_soc_preg, snd_soc_preg_write, | ||
90 | |||
91 | TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, | ||
92 | unsigned int val), | ||
93 | |||
94 | TP_ARGS(platform, reg, val) | ||
95 | |||
96 | ); | ||
97 | |||
98 | DEFINE_EVENT(snd_soc_preg, snd_soc_preg_read, | ||
99 | |||
100 | TP_PROTO(struct snd_soc_platform *platform, unsigned int reg, | ||
101 | unsigned int val), | ||
102 | |||
103 | TP_ARGS(platform, reg, val) | ||
104 | |||
105 | ); | ||
106 | |||
62 | DECLARE_EVENT_CLASS(snd_soc_card, | 107 | DECLARE_EVENT_CLASS(snd_soc_card, |
63 | 108 | ||
64 | TP_PROTO(struct snd_soc_card *card, int val), | 109 | TP_PROTO(struct snd_soc_card *card, int val), |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 1ed61c5df2c5..4f913876f332 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o |
2 | snd-soc-core-objs += soc-pcm.o soc-io.o | ||
2 | 3 | ||
3 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 4 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
4 | obj-$(CONFIG_SND_SOC) += codecs/ | 5 | obj-$(CONFIG_SND_SOC) += codecs/ |
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c index d0e75323ec19..f81d4c3f8956 100644 --- a/sound/soc/atmel/atmel-pcm.c +++ b/sound/soc/atmel/atmel-pcm.c | |||
@@ -364,9 +364,11 @@ static struct snd_pcm_ops atmel_pcm_ops = { | |||
364 | \*--------------------------------------------------------------------------*/ | 364 | \*--------------------------------------------------------------------------*/ |
365 | static u64 atmel_pcm_dmamask = 0xffffffff; | 365 | static u64 atmel_pcm_dmamask = 0xffffffff; |
366 | 366 | ||
367 | static int atmel_pcm_new(struct snd_card *card, | 367 | static int atmel_pcm_new(struct snd_soc_pcm_runtime *rtd) |
368 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
369 | { | 368 | { |
369 | struct snd_card *card = rtd->card->snd_card; | ||
370 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
371 | struct snd_pcm *pcm = rtd->pcm; | ||
370 | int ret = 0; | 372 | int ret = 0; |
371 | 373 | ||
372 | if (!card->dev->dma_mask) | 374 | if (!card->dev->dma_mask) |
@@ -382,7 +384,7 @@ static int atmel_pcm_new(struct snd_card *card, | |||
382 | } | 384 | } |
383 | 385 | ||
384 | if (dai->driver->capture.channels_min) { | 386 | if (dai->driver->capture.channels_min) { |
385 | pr_debug("at32-pcm:" | 387 | pr_debug("atmel-pcm:" |
386 | "Allocating PCM capture DMA buffer\n"); | 388 | "Allocating PCM capture DMA buffer\n"); |
387 | ret = atmel_pcm_preallocate_dma_buffer(pcm, | 389 | ret = atmel_pcm_preallocate_dma_buffer(pcm, |
388 | SNDRV_PCM_STREAM_CAPTURE); | 390 | SNDRV_PCM_STREAM_CAPTURE); |
diff --git a/sound/soc/atmel/atmel-pcm.h b/sound/soc/atmel/atmel-pcm.h index 2597329302e7..5e0a95e64329 100644 --- a/sound/soc/atmel/atmel-pcm.h +++ b/sound/soc/atmel/atmel-pcm.h | |||
@@ -60,7 +60,7 @@ struct atmel_ssc_mask { | |||
60 | * This structure, shared between the PCM driver and the interface, | 60 | * This structure, shared between the PCM driver and the interface, |
61 | * contains all information required by the PCM driver to perform the | 61 | * contains all information required by the PCM driver to perform the |
62 | * PDC DMA operation. All fields except dma_intr_handler() are initialized | 62 | * PDC DMA operation. All fields except dma_intr_handler() are initialized |
63 | * by the interface. The dms_intr_handler() pointer is set by the PCM | 63 | * by the interface. The dma_intr_handler() pointer is set by the PCM |
64 | * driver and called by the interface SSC interrupt handler if it is | 64 | * driver and called by the interface SSC interrupt handler if it is |
65 | * non-NULL. | 65 | * non-NULL. |
66 | */ | 66 | */ |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index eda955b15834..71225090c49f 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -402,7 +402,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
402 | if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S | 402 | if ((ssc_p->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_I2S |
403 | && bits > 16) { | 403 | && bits > 16) { |
404 | printk(KERN_WARNING | 404 | printk(KERN_WARNING |
405 | "atmel_ssc_dai: sample size %d" | 405 | "atmel_ssc_dai: sample size %d " |
406 | "is too large for I2S\n", bits); | 406 | "is too large for I2S\n", bits); |
407 | return -EINVAL; | 407 | return -EINVAL; |
408 | } | 408 | } |
@@ -838,10 +838,8 @@ int atmel_ssc_set_audio(int ssc_id) | |||
838 | } | 838 | } |
839 | 839 | ||
840 | ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); | 840 | ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id); |
841 | if (!ssc_pdev) { | 841 | if (!ssc_pdev) |
842 | ssc_free(ssc); | ||
843 | return -ENOMEM; | 842 | return -ENOMEM; |
844 | } | ||
845 | 843 | ||
846 | /* If we can grab the SSC briefly to parent the DAI device off it */ | 844 | /* If we can grab the SSC briefly to parent the DAI device off it */ |
847 | ssc = ssc_request(ssc_id); | 845 | ssc = ssc_request(ssc_id); |
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index 95572d290c27..bad3aa14d5b3 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
@@ -92,6 +92,7 @@ static struct snd_soc_ops at91sam9g20ek_ops = { | |||
92 | }; | 92 | }; |
93 | 93 | ||
94 | static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, | 94 | static int at91sam9g20ek_set_bias_level(struct snd_soc_card *card, |
95 | struct snd_soc_dapm_context *dapm, | ||
95 | enum snd_soc_bias_level level) | 96 | enum snd_soc_bias_level level) |
96 | { | 97 | { |
97 | static int mclk_on; | 98 | static int mclk_on; |
diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index 10fdd2854e58..20bb53a837b1 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c | |||
@@ -319,10 +319,11 @@ static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
319 | snd_pcm_lib_preallocate_free_for_all(pcm); | 319 | snd_pcm_lib_preallocate_free_for_all(pcm); |
320 | } | 320 | } |
321 | 321 | ||
322 | static int au1xpsc_pcm_new(struct snd_card *card, | 322 | static int au1xpsc_pcm_new(struct snd_soc_pcm_runtime *rtd) |
323 | struct snd_soc_dai *dai, | ||
324 | struct snd_pcm *pcm) | ||
325 | { | 323 | { |
324 | struct snd_card *card = rtd->card->snd_card; | ||
325 | struct snd_pcm *pcm = rtd->pcm; | ||
326 | |||
326 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 327 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
327 | card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); | 328 | card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1); |
328 | 329 | ||
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index ae403597fd31..fe9d548a6837 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
@@ -10,13 +10,36 @@ config SND_BF5XX_I2S | |||
10 | 10 | ||
11 | config SND_BF5XX_SOC_SSM2602 | 11 | config SND_BF5XX_SOC_SSM2602 |
12 | tristate "SoC SSM2602 Audio support for BF52x ezkit" | 12 | tristate "SoC SSM2602 Audio support for BF52x ezkit" |
13 | depends on SND_BF5XX_I2S | 13 | depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) |
14 | select SND_BF5XX_SOC_I2S | 14 | select SND_BF5XX_SOC_I2S |
15 | select SND_SOC_SSM2602 | 15 | select SND_SOC_SSM2602 |
16 | select I2C | ||
17 | help | 16 | help |
18 | Say Y if you want to add support for SoC audio on BF527-EZKIT. | 17 | Say Y if you want to add support for SoC audio on BF527-EZKIT. |
19 | 18 | ||
19 | config SND_SOC_BFIN_EVAL_ADAU1701 | ||
20 | tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" | ||
21 | depends on SND_BF5XX_I2S | ||
22 | select SND_BF5XX_SOC_I2S | ||
23 | select SND_SOC_ADAU1701 | ||
24 | select I2C | ||
25 | help | ||
26 | Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ | ||
27 | board connected to one of the Blackfin evaluation boards like the | ||
28 | BF5XX-STAMP or BF5XX-EZKIT. | ||
29 | |||
30 | config SND_SOC_BFIN_EVAL_ADAV80X | ||
31 | tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" | ||
32 | depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) | ||
33 | select SND_BF5XX_SOC_I2S | ||
34 | select SND_SOC_ADAV80X | ||
35 | help | ||
36 | Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or | ||
37 | EVAL-ADAV803 board connected to one of the Blackfin evaluation boards | ||
38 | like the BF5XX-STAMP or BF5XX-EZKIT. | ||
39 | |||
40 | Note: This driver assumes that the ADAV80X digital record and playback | ||
41 | interfaces are connected to the first SPORT port on the BF5XX board. | ||
42 | |||
20 | config SND_BF5XX_SOC_AD73311 | 43 | config SND_BF5XX_SOC_AD73311 |
21 | tristate "SoC AD73311 Audio support for Blackfin" | 44 | tristate "SoC AD73311 Audio support for Blackfin" |
22 | depends on SND_BF5XX_I2S | 45 | depends on SND_BF5XX_I2S |
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index 49af3f32aec8..6018bf52a234 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile | |||
@@ -21,9 +21,13 @@ snd-ad1980-objs := bf5xx-ad1980.o | |||
21 | snd-ssm2602-objs := bf5xx-ssm2602.o | 21 | snd-ssm2602-objs := bf5xx-ssm2602.o |
22 | snd-ad73311-objs := bf5xx-ad73311.o | 22 | snd-ad73311-objs := bf5xx-ad73311.o |
23 | snd-ad193x-objs := bf5xx-ad193x.o | 23 | snd-ad193x-objs := bf5xx-ad193x.o |
24 | snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o | ||
25 | snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o | ||
24 | 26 | ||
25 | obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o | 27 | obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o |
26 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o | 28 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o |
27 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o | 29 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o |
28 | obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o | 30 | obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o |
29 | obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o | 31 | obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o |
32 | obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o | ||
33 | obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o | ||
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 98b44b316e78..9e59f680bc19 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c | |||
@@ -418,9 +418,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
418 | 418 | ||
419 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); | 419 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); |
420 | 420 | ||
421 | int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai, | 421 | int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd) |
422 | struct snd_pcm *pcm) | ||
423 | { | 422 | { |
423 | struct snd_card *card = rtd->card->snd_card; | ||
424 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
425 | struct snd_pcm *pcm = rtd->pcm; | ||
424 | int ret = 0; | 426 | int ret = 0; |
425 | 427 | ||
426 | pr_debug("%s enter\n", __func__); | 428 | pr_debug("%s enter\n", __func__); |
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index f1fd95bb6416..61ddf942fd4d 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c | |||
@@ -168,7 +168,7 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream) | |||
168 | 168 | ||
169 | snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); | 169 | snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); |
170 | 170 | ||
171 | ret = snd_pcm_hw_constraint_integer(runtime, \ | 171 | ret = snd_pcm_hw_constraint_integer(runtime, |
172 | SNDRV_PCM_HW_PARAM_PERIODS); | 172 | SNDRV_PCM_HW_PARAM_PERIODS); |
173 | if (ret < 0) | 173 | if (ret < 0) |
174 | goto out; | 174 | goto out; |
@@ -257,9 +257,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
257 | 257 | ||
258 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); | 258 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); |
259 | 259 | ||
260 | int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai, | 260 | int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) |
261 | struct snd_pcm *pcm) | ||
262 | { | 261 | { |
262 | struct snd_card *card = rtd->card->snd_card; | ||
263 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
264 | struct snd_pcm *pcm = rtd->pcm; | ||
263 | int ret = 0; | 265 | int ret = 0; |
264 | 266 | ||
265 | pr_debug("%s enter\n", __func__); | 267 | pr_debug("%s enter\n", __func__); |
@@ -304,8 +306,8 @@ static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev) | |||
304 | 306 | ||
305 | static struct platform_driver bfin_i2s_pcm_driver = { | 307 | static struct platform_driver bfin_i2s_pcm_driver = { |
306 | .driver = { | 308 | .driver = { |
307 | .name = "bfin-i2s-pcm-audio", | 309 | .name = "bfin-i2s-pcm-audio", |
308 | .owner = THIS_MODULE, | 310 | .owner = THIS_MODULE, |
309 | }, | 311 | }, |
310 | 312 | ||
311 | .probe = bfin_i2s_soc_platform_probe, | 313 | .probe = bfin_i2s_soc_platform_probe, |
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index 07cfc7a9e49a..c95cc03d583d 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c | |||
@@ -283,9 +283,11 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
283 | 283 | ||
284 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); | 284 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); |
285 | 285 | ||
286 | static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai, | 286 | static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd) |
287 | struct snd_pcm *pcm) | ||
288 | { | 287 | { |
288 | struct snd_card *card = rtd->card->snd_card; | ||
289 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
290 | struct snd_pcm *pcm = rtd->pcm; | ||
289 | int ret = 0; | 291 | int ret = 0; |
290 | 292 | ||
291 | if (!card->dev->dma_mask) | 293 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/blackfin/bfin-eval-adau1701.c b/sound/soc/blackfin/bfin-eval-adau1701.c new file mode 100644 index 000000000000..e5550acba2c2 --- /dev/null +++ b/sound/soc/blackfin/bfin-eval-adau1701.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Machine driver for EVAL-ADAU1701MINIZ on Analog Devices bfin | ||
3 | * evaluation boards. | ||
4 | * | ||
5 | * Copyright 2011 Analog Devices Inc. | ||
6 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include <sound/soc.h> | ||
16 | #include <sound/pcm_params.h> | ||
17 | |||
18 | #include "../codecs/adau1701.h" | ||
19 | |||
20 | static const struct snd_soc_dapm_widget bfin_eval_adau1701_dapm_widgets[] = { | ||
21 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
22 | SND_SOC_DAPM_LINE("Line Out", NULL), | ||
23 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
24 | }; | ||
25 | |||
26 | static const struct snd_soc_dapm_route bfin_eval_adau1701_dapm_routes[] = { | ||
27 | { "Speaker", NULL, "OUT0" }, | ||
28 | { "Speaker", NULL, "OUT1" }, | ||
29 | { "Line Out", NULL, "OUT2" }, | ||
30 | { "Line Out", NULL, "OUT3" }, | ||
31 | |||
32 | { "IN0", NULL, "Line In" }, | ||
33 | { "IN1", NULL, "Line In" }, | ||
34 | }; | ||
35 | |||
36 | static int bfin_eval_adau1701_hw_params(struct snd_pcm_substream *substream, | ||
37 | struct snd_pcm_hw_params *params) | ||
38 | { | ||
39 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
40 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
41 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
42 | int ret; | ||
43 | |||
44 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
45 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
46 | if (ret) | ||
47 | return ret; | ||
48 | |||
49 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
50 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
51 | if (ret) | ||
52 | return ret; | ||
53 | |||
54 | ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1701_CLK_SRC_OSC, 12288000, | ||
55 | SND_SOC_CLOCK_IN); | ||
56 | |||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | static struct snd_soc_ops bfin_eval_adau1701_ops = { | ||
61 | .hw_params = bfin_eval_adau1701_hw_params, | ||
62 | }; | ||
63 | |||
64 | static struct snd_soc_dai_link bfin_eval_adau1701_dai[] = { | ||
65 | { | ||
66 | .name = "adau1701", | ||
67 | .stream_name = "adau1701", | ||
68 | .cpu_dai_name = "bfin-i2s.0", | ||
69 | .codec_dai_name = "adau1701", | ||
70 | .platform_name = "bfin-i2s-pcm-audio", | ||
71 | .codec_name = "adau1701.0-0034", | ||
72 | .ops = &bfin_eval_adau1701_ops, | ||
73 | }, | ||
74 | { | ||
75 | .name = "adau1701", | ||
76 | .stream_name = "adau1701", | ||
77 | .cpu_dai_name = "bfin-i2s.1", | ||
78 | .codec_dai_name = "adau1701", | ||
79 | .platform_name = "bfin-i2s-pcm-audio", | ||
80 | .codec_name = "adau1701.0-0034", | ||
81 | .ops = &bfin_eval_adau1701_ops, | ||
82 | }, | ||
83 | }; | ||
84 | |||
85 | static struct snd_soc_card bfin_eval_adau1701 = { | ||
86 | .name = "bfin-eval-adau1701", | ||
87 | .dai_link = &bfin_eval_adau1701_dai[CONFIG_SND_BF5XX_SPORT_NUM], | ||
88 | .num_links = 1, | ||
89 | |||
90 | .dapm_widgets = bfin_eval_adau1701_dapm_widgets, | ||
91 | .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1701_dapm_widgets), | ||
92 | .dapm_routes = bfin_eval_adau1701_dapm_routes, | ||
93 | .num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1701_dapm_routes), | ||
94 | }; | ||
95 | |||
96 | static int bfin_eval_adau1701_probe(struct platform_device *pdev) | ||
97 | { | ||
98 | struct snd_soc_card *card = &bfin_eval_adau1701; | ||
99 | |||
100 | card->dev = &pdev->dev; | ||
101 | |||
102 | return snd_soc_register_card(&bfin_eval_adau1701); | ||
103 | } | ||
104 | |||
105 | static int __devexit bfin_eval_adau1701_remove(struct platform_device *pdev) | ||
106 | { | ||
107 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
108 | |||
109 | snd_soc_unregister_card(card); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static struct platform_driver bfin_eval_adau1701_driver = { | ||
115 | .driver = { | ||
116 | .name = "bfin-eval-adau1701", | ||
117 | .owner = THIS_MODULE, | ||
118 | .pm = &snd_soc_pm_ops, | ||
119 | }, | ||
120 | .probe = bfin_eval_adau1701_probe, | ||
121 | .remove = __devexit_p(bfin_eval_adau1701_remove), | ||
122 | }; | ||
123 | |||
124 | static int __init bfin_eval_adau1701_init(void) | ||
125 | { | ||
126 | return platform_driver_register(&bfin_eval_adau1701_driver); | ||
127 | } | ||
128 | module_init(bfin_eval_adau1701_init); | ||
129 | |||
130 | static void __exit bfin_eval_adau1701_exit(void) | ||
131 | { | ||
132 | platform_driver_unregister(&bfin_eval_adau1701_driver); | ||
133 | } | ||
134 | module_exit(bfin_eval_adau1701_exit); | ||
135 | |||
136 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
137 | MODULE_DESCRIPTION("ALSA SoC bfin ADAU1701 driver"); | ||
138 | MODULE_LICENSE("GPL"); | ||
139 | MODULE_ALIAS("platform:bfin-eval-adau1701"); | ||
diff --git a/sound/soc/blackfin/bfin-eval-adav80x.c b/sound/soc/blackfin/bfin-eval-adav80x.c new file mode 100644 index 000000000000..8d014d01626e --- /dev/null +++ b/sound/soc/blackfin/bfin-eval-adav80x.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Machine driver for EVAL-ADAV801 and EVAL-ADAV803 on Analog Devices bfin | ||
3 | * evaluation boards. | ||
4 | * | ||
5 | * Copyright 2011 Analog Devices Inc. | ||
6 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <sound/core.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include <sound/soc.h> | ||
16 | |||
17 | #include "../codecs/adav80x.h" | ||
18 | |||
19 | static const struct snd_soc_dapm_widget bfin_eval_adav80x_dapm_widgets[] = { | ||
20 | SND_SOC_DAPM_LINE("Line Out", NULL), | ||
21 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
22 | }; | ||
23 | |||
24 | static const struct snd_soc_dapm_route bfin_eval_adav80x_dapm_routes[] = { | ||
25 | { "Line Out", NULL, "VOUTL" }, | ||
26 | { "Line Out", NULL, "VOUTR" }, | ||
27 | |||
28 | { "VINL", NULL, "Line In" }, | ||
29 | { "VINR", NULL, "Line In" }, | ||
30 | }; | ||
31 | |||
32 | static int bfin_eval_adav80x_hw_params(struct snd_pcm_substream *substream, | ||
33 | struct snd_pcm_hw_params *params) | ||
34 | { | ||
35 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
36 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
37 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
38 | int ret; | ||
39 | |||
40 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
41 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
42 | if (ret) | ||
43 | return ret; | ||
44 | |||
45 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
46 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM); | ||
47 | if (ret) | ||
48 | return ret; | ||
49 | |||
50 | ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_PLL1, ADAV80X_PLL_SRC_XTAL, | ||
51 | 27000000, params_rate(params) * 256); | ||
52 | if (ret) | ||
53 | return ret; | ||
54 | |||
55 | ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_PLL1, | ||
56 | params_rate(params) * 256, SND_SOC_CLOCK_IN); | ||
57 | |||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | static int bfin_eval_adav80x_codec_init(struct snd_soc_pcm_runtime *rtd) | ||
62 | { | ||
63 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
64 | |||
65 | snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK1, 0, | ||
66 | SND_SOC_CLOCK_OUT); | ||
67 | snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK2, 0, | ||
68 | SND_SOC_CLOCK_OUT); | ||
69 | snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_SYSCLK3, 0, | ||
70 | SND_SOC_CLOCK_OUT); | ||
71 | |||
72 | snd_soc_dai_set_sysclk(codec_dai, ADAV80X_CLK_XTAL, 2700000, 0); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static struct snd_soc_ops bfin_eval_adav80x_ops = { | ||
78 | .hw_params = bfin_eval_adav80x_hw_params, | ||
79 | }; | ||
80 | |||
81 | static struct snd_soc_dai_link bfin_eval_adav80x_dais[] = { | ||
82 | { | ||
83 | .name = "adav80x", | ||
84 | .stream_name = "ADAV80x HiFi", | ||
85 | .cpu_dai_name = "bfin-i2s.0", | ||
86 | .codec_dai_name = "adav80x-hifi", | ||
87 | .platform_name = "bfin-i2s-pcm-audio", | ||
88 | .init = bfin_eval_adav80x_codec_init, | ||
89 | .ops = &bfin_eval_adav80x_ops, | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | static struct snd_soc_card bfin_eval_adav80x = { | ||
94 | .name = "bfin-eval-adav80x", | ||
95 | .dai_link = bfin_eval_adav80x_dais, | ||
96 | .num_links = ARRAY_SIZE(bfin_eval_adav80x_dais), | ||
97 | |||
98 | .dapm_widgets = bfin_eval_adav80x_dapm_widgets, | ||
99 | .num_dapm_widgets = ARRAY_SIZE(bfin_eval_adav80x_dapm_widgets), | ||
100 | .dapm_routes = bfin_eval_adav80x_dapm_routes, | ||
101 | .num_dapm_routes = ARRAY_SIZE(bfin_eval_adav80x_dapm_routes), | ||
102 | }; | ||
103 | |||
104 | enum bfin_eval_adav80x_type { | ||
105 | BFIN_EVAL_ADAV801, | ||
106 | BFIN_EVAL_ADAV803, | ||
107 | }; | ||
108 | |||
109 | static int bfin_eval_adav80x_probe(struct platform_device *pdev) | ||
110 | { | ||
111 | struct snd_soc_card *card = &bfin_eval_adav80x; | ||
112 | const char *codec_name; | ||
113 | |||
114 | switch (platform_get_device_id(pdev)->driver_data) { | ||
115 | case BFIN_EVAL_ADAV801: | ||
116 | codec_name = "spi0.1"; | ||
117 | break; | ||
118 | case BFIN_EVAL_ADAV803: | ||
119 | codec_name = "adav803.0-0034"; | ||
120 | break; | ||
121 | default: | ||
122 | return -EINVAL; | ||
123 | } | ||
124 | |||
125 | bfin_eval_adav80x_dais[0].codec_name = codec_name; | ||
126 | |||
127 | card->dev = &pdev->dev; | ||
128 | |||
129 | return snd_soc_register_card(&bfin_eval_adav80x); | ||
130 | } | ||
131 | |||
132 | static int __devexit bfin_eval_adav80x_remove(struct platform_device *pdev) | ||
133 | { | ||
134 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
135 | |||
136 | snd_soc_unregister_card(card); | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static const struct platform_device_id bfin_eval_adav80x_ids[] = { | ||
142 | { "bfin-eval-adav801", BFIN_EVAL_ADAV801 }, | ||
143 | { "bfin-eval-adav803", BFIN_EVAL_ADAV803 }, | ||
144 | { }, | ||
145 | }; | ||
146 | MODULE_DEVICE_TABLE(platform, bfin_eval_adav80x_ids); | ||
147 | |||
148 | static struct platform_driver bfin_eval_adav80x_driver = { | ||
149 | .driver = { | ||
150 | .name = "bfin-eval-adav80x", | ||
151 | .owner = THIS_MODULE, | ||
152 | .pm = &snd_soc_pm_ops, | ||
153 | }, | ||
154 | .probe = bfin_eval_adav80x_probe, | ||
155 | .remove = __devexit_p(bfin_eval_adav80x_remove), | ||
156 | .id_table = bfin_eval_adav80x_ids, | ||
157 | }; | ||
158 | |||
159 | static int __init bfin_eval_adav80x_init(void) | ||
160 | { | ||
161 | return platform_driver_register(&bfin_eval_adav80x_driver); | ||
162 | } | ||
163 | module_init(bfin_eval_adav80x_init); | ||
164 | |||
165 | static void __exit bfin_eval_adav80x_exit(void) | ||
166 | { | ||
167 | platform_driver_unregister(&bfin_eval_adav80x_driver); | ||
168 | } | ||
169 | module_exit(bfin_eval_adav80x_exit); | ||
170 | |||
171 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
172 | MODULE_DESCRIPTION("ALSA SoC bfin adav80x driver"); | ||
173 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 98175a096df2..ff43405752a1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS | |||
17 | select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI | 17 | select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI |
18 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS | 18 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS |
19 | select SND_SOC_AD73311 | 19 | select SND_SOC_AD73311 |
20 | select SND_SOC_ADAV80X | ||
20 | select SND_SOC_ADS117X | 21 | select SND_SOC_ADS117X |
21 | select SND_SOC_AK4104 if SPI_MASTER | 22 | select SND_SOC_AK4104 if SPI_MASTER |
22 | select SND_SOC_AK4535 if I2C | 23 | select SND_SOC_AK4535 if I2C |
@@ -42,6 +43,7 @@ config SND_SOC_ALL_CODECS | |||
42 | select SND_SOC_SN95031 if INTEL_SCU_IPC | 43 | select SND_SOC_SN95031 if INTEL_SCU_IPC |
43 | select SND_SOC_SPDIF | 44 | select SND_SOC_SPDIF |
44 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI | 45 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI |
46 | select SND_SOC_STA32X if I2C | ||
45 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 47 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
46 | select SND_SOC_TLV320AIC23 if I2C | 48 | select SND_SOC_TLV320AIC23 if I2C |
47 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 49 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
@@ -71,6 +73,7 @@ config SND_SOC_ALL_CODECS | |||
71 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI | 73 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI |
72 | select SND_SOC_WM8770 if SPI_MASTER | 74 | select SND_SOC_WM8770 if SPI_MASTER |
73 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI | 75 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI |
76 | select SND_SOC_WM8782 | ||
74 | select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI | 77 | select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI |
75 | select SND_SOC_WM8900 if I2C | 78 | select SND_SOC_WM8900 if I2C |
76 | select SND_SOC_WM8903 if I2C | 79 | select SND_SOC_WM8903 if I2C |
@@ -130,7 +133,14 @@ config SND_SOC_AD1980 | |||
130 | 133 | ||
131 | config SND_SOC_AD73311 | 134 | config SND_SOC_AD73311 |
132 | tristate | 135 | tristate |
133 | 136 | ||
137 | config SND_SOC_ADAU1701 | ||
138 | select SIGMA | ||
139 | tristate | ||
140 | |||
141 | config SND_SOC_ADAV80X | ||
142 | tristate | ||
143 | |||
134 | config SND_SOC_ADS117X | 144 | config SND_SOC_ADS117X |
135 | tristate | 145 | tristate |
136 | 146 | ||
@@ -216,6 +226,9 @@ config SND_SOC_SPDIF | |||
216 | config SND_SOC_SSM2602 | 226 | config SND_SOC_SSM2602 |
217 | tristate | 227 | tristate |
218 | 228 | ||
229 | config SND_SOC_STA32X | ||
230 | tristate | ||
231 | |||
219 | config SND_SOC_STAC9766 | 232 | config SND_SOC_STAC9766 |
220 | tristate | 233 | tristate |
221 | 234 | ||
@@ -299,6 +312,9 @@ config SND_SOC_WM8770 | |||
299 | config SND_SOC_WM8776 | 312 | config SND_SOC_WM8776 |
300 | tristate | 313 | tristate |
301 | 314 | ||
315 | config SND_SOC_WM8782 | ||
316 | tristate | ||
317 | |||
302 | config SND_SOC_WM8804 | 318 | config SND_SOC_WM8804 |
303 | tristate | 319 | tristate |
304 | 320 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fd8558406ef0..4957431e23fc 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -4,6 +4,8 @@ snd-soc-ad1836-objs := ad1836.o | |||
4 | snd-soc-ad193x-objs := ad193x.o | 4 | snd-soc-ad193x-objs := ad193x.o |
5 | snd-soc-ad1980-objs := ad1980.o | 5 | snd-soc-ad1980-objs := ad1980.o |
6 | snd-soc-ad73311-objs := ad73311.o | 6 | snd-soc-ad73311-objs := ad73311.o |
7 | snd-soc-adau1701-objs := adau1701.o | ||
8 | snd-soc-adav80x-objs := adav80x.o | ||
7 | snd-soc-ads117x-objs := ads117x.o | 9 | snd-soc-ads117x-objs := ads117x.o |
8 | snd-soc-ak4104-objs := ak4104.o | 10 | snd-soc-ak4104-objs := ak4104.o |
9 | snd-soc-ak4535-objs := ak4535.o | 11 | snd-soc-ak4535-objs := ak4535.o |
@@ -28,6 +30,7 @@ snd-soc-alc5623-objs := alc5623.o | |||
28 | snd-soc-sn95031-objs := sn95031.o | 30 | snd-soc-sn95031-objs := sn95031.o |
29 | snd-soc-spdif-objs := spdif_transciever.o | 31 | snd-soc-spdif-objs := spdif_transciever.o |
30 | snd-soc-ssm2602-objs := ssm2602.o | 32 | snd-soc-ssm2602-objs := ssm2602.o |
33 | snd-soc-sta32x-objs := sta32x.o | ||
31 | snd-soc-stac9766-objs := stac9766.o | 34 | snd-soc-stac9766-objs := stac9766.o |
32 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 35 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
33 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 36 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
@@ -55,6 +58,7 @@ snd-soc-wm8750-objs := wm8750.o | |||
55 | snd-soc-wm8753-objs := wm8753.o | 58 | snd-soc-wm8753-objs := wm8753.o |
56 | snd-soc-wm8770-objs := wm8770.o | 59 | snd-soc-wm8770-objs := wm8770.o |
57 | snd-soc-wm8776-objs := wm8776.o | 60 | snd-soc-wm8776-objs := wm8776.o |
61 | snd-soc-wm8782-objs := wm8782.o | ||
58 | snd-soc-wm8804-objs := wm8804.o | 62 | snd-soc-wm8804-objs := wm8804.o |
59 | snd-soc-wm8900-objs := wm8900.o | 63 | snd-soc-wm8900-objs := wm8900.o |
60 | snd-soc-wm8903-objs := wm8903.o | 64 | snd-soc-wm8903-objs := wm8903.o |
@@ -95,6 +99,8 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o | |||
95 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o | 99 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o |
96 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 100 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
97 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 101 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
102 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o | ||
103 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o | ||
98 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o | 104 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o |
99 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 105 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
100 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 106 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
@@ -120,6 +126,7 @@ obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | |||
120 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | 126 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o |
121 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 127 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
122 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 128 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
129 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o | ||
123 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 130 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
124 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 131 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
125 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 132 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
@@ -147,6 +154,7 @@ obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | |||
147 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 154 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
148 | obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o | 155 | obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o |
149 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o | 156 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o |
157 | obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o | ||
150 | obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o | 158 | obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o |
151 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o | 159 | obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o |
152 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o | 160 | obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 754c496412bd..4e5c5726366b 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -1,19 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * File: sound/soc/codecs/ad1836.c | 2 | * Audio Codec driver supporting: |
3 | * Author: Barry Song <Barry.Song@analog.com> | 3 | * AD1835A, AD1836, AD1837A, AD1838A, AD1839A |
4 | * | ||
5 | * Created: Aug 04 2009 | ||
6 | * Description: Driver for AD1836 sound chip | ||
7 | * | ||
8 | * Modified: | ||
9 | * Copyright 2009 Analog Devices Inc. | ||
10 | * | 4 | * |
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | 5 | * Copyright 2009-2011 Analog Devices Inc. |
12 | * | 6 | * |
13 | * This program is free software; you can redistribute it and/or modify | 7 | * Licensed under the GPL-2 or later. |
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | */ | 8 | */ |
18 | 9 | ||
19 | #include <linux/init.h> | 10 | #include <linux/init.h> |
@@ -30,10 +21,15 @@ | |||
30 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
31 | #include "ad1836.h" | 22 | #include "ad1836.h" |
32 | 23 | ||
24 | enum ad1836_type { | ||
25 | AD1835, | ||
26 | AD1836, | ||
27 | AD1838, | ||
28 | }; | ||
29 | |||
33 | /* codec private data */ | 30 | /* codec private data */ |
34 | struct ad1836_priv { | 31 | struct ad1836_priv { |
35 | enum snd_soc_control_type control_type; | 32 | enum ad1836_type type; |
36 | void *control_data; | ||
37 | }; | 33 | }; |
38 | 34 | ||
39 | /* | 35 | /* |
@@ -44,29 +40,60 @@ static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; | |||
44 | static const struct soc_enum ad1836_deemp_enum = | 40 | static const struct soc_enum ad1836_deemp_enum = |
45 | SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); | 41 | SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); |
46 | 42 | ||
47 | static const struct snd_kcontrol_new ad1836_snd_controls[] = { | 43 | #define AD1836_DAC_VOLUME(x) \ |
48 | /* DAC volume control */ | 44 | SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ |
49 | SOC_DOUBLE_R("DAC1 Volume", AD1836_DAC_L1_VOL, | 45 | AD1836_DAC_R_VOL(x), 0, 0x3FF, 0) |
50 | AD1836_DAC_R1_VOL, 0, 0x3FF, 0), | 46 | |
51 | SOC_DOUBLE_R("DAC2 Volume", AD1836_DAC_L2_VOL, | 47 | #define AD1836_DAC_SWITCH(x) \ |
52 | AD1836_DAC_R2_VOL, 0, 0x3FF, 0), | 48 | SOC_DOUBLE("DAC" #x " Playback Switch", AD1836_DAC_CTRL2, \ |
53 | SOC_DOUBLE_R("DAC3 Volume", AD1836_DAC_L3_VOL, | 49 | AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) |
54 | AD1836_DAC_R3_VOL, 0, 0x3FF, 0), | 50 | |
55 | 51 | #define AD1836_ADC_SWITCH(x) \ | |
56 | /* ADC switch control */ | 52 | SOC_DOUBLE("ADC" #x " Capture Switch", AD1836_ADC_CTRL2, \ |
57 | SOC_DOUBLE("ADC1 Switch", AD1836_ADC_CTRL2, AD1836_ADCL1_MUTE, | 53 | AD1836_MUTE_LEFT(x), AD1836_MUTE_RIGHT(x), 1, 1) |
58 | AD1836_ADCR1_MUTE, 1, 1), | 54 | |
59 | SOC_DOUBLE("ADC2 Switch", AD1836_ADC_CTRL2, AD1836_ADCL2_MUTE, | 55 | static const struct snd_kcontrol_new ad183x_dac_controls[] = { |
60 | AD1836_ADCR2_MUTE, 1, 1), | 56 | AD1836_DAC_VOLUME(1), |
61 | 57 | AD1836_DAC_SWITCH(1), | |
62 | /* DAC switch control */ | 58 | AD1836_DAC_VOLUME(2), |
63 | SOC_DOUBLE("DAC1 Switch", AD1836_DAC_CTRL2, AD1836_DACL1_MUTE, | 59 | AD1836_DAC_SWITCH(2), |
64 | AD1836_DACR1_MUTE, 1, 1), | 60 | AD1836_DAC_VOLUME(3), |
65 | SOC_DOUBLE("DAC2 Switch", AD1836_DAC_CTRL2, AD1836_DACL2_MUTE, | 61 | AD1836_DAC_SWITCH(3), |
66 | AD1836_DACR2_MUTE, 1, 1), | 62 | AD1836_DAC_VOLUME(4), |
67 | SOC_DOUBLE("DAC3 Switch", AD1836_DAC_CTRL2, AD1836_DACL3_MUTE, | 63 | AD1836_DAC_SWITCH(4), |
68 | AD1836_DACR3_MUTE, 1, 1), | 64 | }; |
65 | |||
66 | static const struct snd_soc_dapm_widget ad183x_dac_dapm_widgets[] = { | ||
67 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), | ||
68 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), | ||
69 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), | ||
70 | SND_SOC_DAPM_OUTPUT("DAC4OUT"), | ||
71 | }; | ||
72 | |||
73 | static const struct snd_soc_dapm_route ad183x_dac_routes[] = { | ||
74 | { "DAC1OUT", NULL, "DAC" }, | ||
75 | { "DAC2OUT", NULL, "DAC" }, | ||
76 | { "DAC3OUT", NULL, "DAC" }, | ||
77 | { "DAC4OUT", NULL, "DAC" }, | ||
78 | }; | ||
79 | |||
80 | static const struct snd_kcontrol_new ad183x_adc_controls[] = { | ||
81 | AD1836_ADC_SWITCH(1), | ||
82 | AD1836_ADC_SWITCH(2), | ||
83 | AD1836_ADC_SWITCH(3), | ||
84 | }; | ||
85 | |||
86 | static const struct snd_soc_dapm_widget ad183x_adc_dapm_widgets[] = { | ||
87 | SND_SOC_DAPM_INPUT("ADC1IN"), | ||
88 | SND_SOC_DAPM_INPUT("ADC2IN"), | ||
89 | }; | ||
90 | |||
91 | static const struct snd_soc_dapm_route ad183x_adc_routes[] = { | ||
92 | { "ADC", NULL, "ADC1IN" }, | ||
93 | { "ADC", NULL, "ADC2IN" }, | ||
94 | }; | ||
69 | 95 | ||
96 | static const struct snd_kcontrol_new ad183x_controls[] = { | ||
70 | /* ADC high-pass filter */ | 97 | /* ADC high-pass filter */ |
71 | SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1, | 98 | SOC_SINGLE("ADC High Pass Filter Switch", AD1836_ADC_CTRL1, |
72 | AD1836_ADC_HIGHPASS_FILTER, 1, 0), | 99 | AD1836_ADC_HIGHPASS_FILTER, 1, 0), |
@@ -75,27 +102,24 @@ static const struct snd_kcontrol_new ad1836_snd_controls[] = { | |||
75 | SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum), | 102 | SOC_ENUM("Playback Deemphasis", ad1836_deemp_enum), |
76 | }; | 103 | }; |
77 | 104 | ||
78 | static const struct snd_soc_dapm_widget ad1836_dapm_widgets[] = { | 105 | static const struct snd_soc_dapm_widget ad183x_dapm_widgets[] = { |
79 | SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1, | 106 | SND_SOC_DAPM_DAC("DAC", "Playback", AD1836_DAC_CTRL1, |
80 | AD1836_DAC_POWERDOWN, 1), | 107 | AD1836_DAC_POWERDOWN, 1), |
81 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), | 108 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), |
82 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1, | 109 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1836_ADC_CTRL1, |
83 | AD1836_ADC_POWERDOWN, 1, NULL, 0), | 110 | AD1836_ADC_POWERDOWN, 1, NULL, 0), |
84 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), | ||
85 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), | ||
86 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), | ||
87 | SND_SOC_DAPM_INPUT("ADC1IN"), | ||
88 | SND_SOC_DAPM_INPUT("ADC2IN"), | ||
89 | }; | 111 | }; |
90 | 112 | ||
91 | static const struct snd_soc_dapm_route audio_paths[] = { | 113 | static const struct snd_soc_dapm_route ad183x_dapm_routes[] = { |
92 | { "DAC", NULL, "ADC_PWR" }, | 114 | { "DAC", NULL, "ADC_PWR" }, |
93 | { "ADC", NULL, "ADC_PWR" }, | 115 | { "ADC", NULL, "ADC_PWR" }, |
94 | { "DAC1OUT", "DAC1 Switch", "DAC" }, | 116 | }; |
95 | { "DAC2OUT", "DAC2 Switch", "DAC" }, | 117 | |
96 | { "DAC3OUT", "DAC3 Switch", "DAC" }, | 118 | static const DECLARE_TLV_DB_SCALE(ad1836_in_tlv, 0, 300, 0); |
97 | { "ADC", "ADC1 Switch", "ADC1IN" }, | 119 | |
98 | { "ADC", "ADC2 Switch", "ADC2IN" }, | 120 | static const struct snd_kcontrol_new ad1836_controls[] = { |
121 | SOC_DOUBLE_TLV("ADC2 Capture Volume", AD1836_ADC_CTRL1, 3, 0, 4, 0, | ||
122 | ad1836_in_tlv), | ||
99 | }; | 123 | }; |
100 | 124 | ||
101 | /* | 125 | /* |
@@ -165,64 +189,69 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, | |||
165 | return 0; | 189 | return 0; |
166 | } | 190 | } |
167 | 191 | ||
192 | static struct snd_soc_dai_ops ad1836_dai_ops = { | ||
193 | .hw_params = ad1836_hw_params, | ||
194 | .set_fmt = ad1836_set_dai_fmt, | ||
195 | }; | ||
196 | |||
197 | #define AD183X_DAI(_name, num_dacs, num_adcs) \ | ||
198 | { \ | ||
199 | .name = _name "-hifi", \ | ||
200 | .playback = { \ | ||
201 | .stream_name = "Playback", \ | ||
202 | .channels_min = 2, \ | ||
203 | .channels_max = (num_dacs) * 2, \ | ||
204 | .rates = SNDRV_PCM_RATE_48000, \ | ||
205 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
206 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \ | ||
207 | }, \ | ||
208 | .capture = { \ | ||
209 | .stream_name = "Capture", \ | ||
210 | .channels_min = 2, \ | ||
211 | .channels_max = (num_adcs) * 2, \ | ||
212 | .rates = SNDRV_PCM_RATE_48000, \ | ||
213 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
214 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, \ | ||
215 | }, \ | ||
216 | .ops = &ad1836_dai_ops, \ | ||
217 | } | ||
218 | |||
219 | static struct snd_soc_dai_driver ad183x_dais[] = { | ||
220 | [AD1835] = AD183X_DAI("ad1835", 4, 1), | ||
221 | [AD1836] = AD183X_DAI("ad1836", 3, 2), | ||
222 | [AD1838] = AD183X_DAI("ad1838", 3, 1), | ||
223 | }; | ||
224 | |||
168 | #ifdef CONFIG_PM | 225 | #ifdef CONFIG_PM |
169 | static int ad1836_soc_suspend(struct snd_soc_codec *codec, | 226 | static int ad1836_suspend(struct snd_soc_codec *codec, pm_message_t state) |
170 | pm_message_t state) | ||
171 | { | 227 | { |
172 | /* reset clock control mode */ | 228 | /* reset clock control mode */ |
173 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); | 229 | return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, |
174 | adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; | 230 | AD1836_ADC_SERFMT_MASK, 0); |
175 | |||
176 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); | ||
177 | } | 231 | } |
178 | 232 | ||
179 | static int ad1836_soc_resume(struct snd_soc_codec *codec) | 233 | static int ad1836_resume(struct snd_soc_codec *codec) |
180 | { | 234 | { |
181 | /* restore clock control mode */ | 235 | /* restore clock control mode */ |
182 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); | 236 | return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, |
183 | adc_ctrl2 |= AD1836_ADC_AUX; | 237 | AD1836_ADC_SERFMT_MASK, AD1836_ADC_AUX); |
184 | |||
185 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); | ||
186 | } | 238 | } |
187 | #else | 239 | #else |
188 | #define ad1836_soc_suspend NULL | 240 | #define ad1836_suspend NULL |
189 | #define ad1836_soc_resume NULL | 241 | #define ad1836_resume NULL |
190 | #endif | 242 | #endif |
191 | 243 | ||
192 | static struct snd_soc_dai_ops ad1836_dai_ops = { | ||
193 | .hw_params = ad1836_hw_params, | ||
194 | .set_fmt = ad1836_set_dai_fmt, | ||
195 | }; | ||
196 | |||
197 | /* codec DAI instance */ | ||
198 | static struct snd_soc_dai_driver ad1836_dai = { | ||
199 | .name = "ad1836-hifi", | ||
200 | .playback = { | ||
201 | .stream_name = "Playback", | ||
202 | .channels_min = 2, | ||
203 | .channels_max = 6, | ||
204 | .rates = SNDRV_PCM_RATE_48000, | ||
205 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | | ||
206 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, | ||
207 | }, | ||
208 | .capture = { | ||
209 | .stream_name = "Capture", | ||
210 | .channels_min = 2, | ||
211 | .channels_max = 4, | ||
212 | .rates = SNDRV_PCM_RATE_48000, | ||
213 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE | | ||
214 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE, | ||
215 | }, | ||
216 | .ops = &ad1836_dai_ops, | ||
217 | }; | ||
218 | |||
219 | static int ad1836_probe(struct snd_soc_codec *codec) | 244 | static int ad1836_probe(struct snd_soc_codec *codec) |
220 | { | 245 | { |
221 | struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); | 246 | struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); |
222 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 247 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
248 | int num_dacs, num_adcs; | ||
223 | int ret = 0; | 249 | int ret = 0; |
250 | int i; | ||
251 | |||
252 | num_dacs = ad183x_dais[ad1836->type].playback.channels_max / 2; | ||
253 | num_adcs = ad183x_dais[ad1836->type].capture.channels_max / 2; | ||
224 | 254 | ||
225 | codec->control_data = ad1836->control_data; | ||
226 | ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); | 255 | ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); |
227 | if (ret < 0) { | 256 | if (ret < 0) { |
228 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | 257 | dev_err(codec->dev, "failed to set cache I/O: %d\n", |
@@ -239,21 +268,46 @@ static int ad1836_probe(struct snd_soc_codec *codec) | |||
239 | snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); | 268 | snd_soc_write(codec, AD1836_ADC_CTRL1, 0x100); |
240 | /* unmute adc channles, adc aux mode */ | 269 | /* unmute adc channles, adc aux mode */ |
241 | snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); | 270 | snd_soc_write(codec, AD1836_ADC_CTRL2, 0x180); |
242 | /* left/right diff:PGA/MUX */ | ||
243 | snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); | ||
244 | /* volume */ | 271 | /* volume */ |
245 | snd_soc_write(codec, AD1836_DAC_L1_VOL, 0x3FF); | 272 | for (i = 1; i <= num_dacs; ++i) { |
246 | snd_soc_write(codec, AD1836_DAC_R1_VOL, 0x3FF); | 273 | snd_soc_write(codec, AD1836_DAC_L_VOL(i), 0x3FF); |
247 | snd_soc_write(codec, AD1836_DAC_L2_VOL, 0x3FF); | 274 | snd_soc_write(codec, AD1836_DAC_R_VOL(i), 0x3FF); |
248 | snd_soc_write(codec, AD1836_DAC_R2_VOL, 0x3FF); | 275 | } |
249 | snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); | 276 | |
250 | snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); | 277 | if (ad1836->type == AD1836) { |
251 | 278 | /* left/right diff:PGA/MUX */ | |
252 | snd_soc_add_controls(codec, ad1836_snd_controls, | 279 | snd_soc_write(codec, AD1836_ADC_CTRL3, 0x3A); |
253 | ARRAY_SIZE(ad1836_snd_controls)); | 280 | ret = snd_soc_add_controls(codec, ad1836_controls, |
254 | snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets, | 281 | ARRAY_SIZE(ad1836_controls)); |
255 | ARRAY_SIZE(ad1836_dapm_widgets)); | 282 | if (ret) |
256 | snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); | 283 | return ret; |
284 | } else { | ||
285 | snd_soc_write(codec, AD1836_ADC_CTRL3, 0x00); | ||
286 | } | ||
287 | |||
288 | ret = snd_soc_add_controls(codec, ad183x_dac_controls, num_dacs * 2); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | ret = snd_soc_add_controls(codec, ad183x_adc_controls, num_adcs); | ||
293 | if (ret) | ||
294 | return ret; | ||
295 | |||
296 | ret = snd_soc_dapm_new_controls(dapm, ad183x_dac_dapm_widgets, num_dacs); | ||
297 | if (ret) | ||
298 | return ret; | ||
299 | |||
300 | ret = snd_soc_dapm_new_controls(dapm, ad183x_adc_dapm_widgets, num_adcs); | ||
301 | if (ret) | ||
302 | return ret; | ||
303 | |||
304 | ret = snd_soc_dapm_add_routes(dapm, ad183x_dac_routes, num_dacs); | ||
305 | if (ret) | ||
306 | return ret; | ||
307 | |||
308 | ret = snd_soc_dapm_add_routes(dapm, ad183x_adc_routes, num_adcs); | ||
309 | if (ret) | ||
310 | return ret; | ||
257 | 311 | ||
258 | return ret; | 312 | return ret; |
259 | } | 313 | } |
@@ -262,19 +316,24 @@ static int ad1836_probe(struct snd_soc_codec *codec) | |||
262 | static int ad1836_remove(struct snd_soc_codec *codec) | 316 | static int ad1836_remove(struct snd_soc_codec *codec) |
263 | { | 317 | { |
264 | /* reset clock control mode */ | 318 | /* reset clock control mode */ |
265 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); | 319 | return snd_soc_update_bits(codec, AD1836_ADC_CTRL2, |
266 | adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; | 320 | AD1836_ADC_SERFMT_MASK, 0); |
267 | |||
268 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); | ||
269 | } | 321 | } |
270 | 322 | ||
271 | static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { | 323 | static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { |
272 | .probe = ad1836_probe, | 324 | .probe = ad1836_probe, |
273 | .remove = ad1836_remove, | 325 | .remove = ad1836_remove, |
274 | .suspend = ad1836_soc_suspend, | 326 | .suspend = ad1836_suspend, |
275 | .resume = ad1836_soc_resume, | 327 | .resume = ad1836_resume, |
276 | .reg_cache_size = AD1836_NUM_REGS, | 328 | .reg_cache_size = AD1836_NUM_REGS, |
277 | .reg_word_size = sizeof(u16), | 329 | .reg_word_size = sizeof(u16), |
330 | |||
331 | .controls = ad183x_controls, | ||
332 | .num_controls = ARRAY_SIZE(ad183x_controls), | ||
333 | .dapm_widgets = ad183x_dapm_widgets, | ||
334 | .num_dapm_widgets = ARRAY_SIZE(ad183x_dapm_widgets), | ||
335 | .dapm_routes = ad183x_dapm_routes, | ||
336 | .num_dapm_routes = ARRAY_SIZE(ad183x_dapm_routes), | ||
278 | }; | 337 | }; |
279 | 338 | ||
280 | static int __devinit ad1836_spi_probe(struct spi_device *spi) | 339 | static int __devinit ad1836_spi_probe(struct spi_device *spi) |
@@ -286,12 +345,12 @@ static int __devinit ad1836_spi_probe(struct spi_device *spi) | |||
286 | if (ad1836 == NULL) | 345 | if (ad1836 == NULL) |
287 | return -ENOMEM; | 346 | return -ENOMEM; |
288 | 347 | ||
348 | ad1836->type = spi_get_device_id(spi)->driver_data; | ||
349 | |||
289 | spi_set_drvdata(spi, ad1836); | 350 | spi_set_drvdata(spi, ad1836); |
290 | ad1836->control_data = spi; | ||
291 | ad1836->control_type = SND_SOC_SPI; | ||
292 | 351 | ||
293 | ret = snd_soc_register_codec(&spi->dev, | 352 | ret = snd_soc_register_codec(&spi->dev, |
294 | &soc_codec_dev_ad1836, &ad1836_dai, 1); | 353 | &soc_codec_dev_ad1836, &ad183x_dais[ad1836->type], 1); |
295 | if (ret < 0) | 354 | if (ret < 0) |
296 | kfree(ad1836); | 355 | kfree(ad1836); |
297 | return ret; | 356 | return ret; |
@@ -303,27 +362,29 @@ static int __devexit ad1836_spi_remove(struct spi_device *spi) | |||
303 | kfree(spi_get_drvdata(spi)); | 362 | kfree(spi_get_drvdata(spi)); |
304 | return 0; | 363 | return 0; |
305 | } | 364 | } |
365 | static const struct spi_device_id ad1836_ids[] = { | ||
366 | { "ad1835", AD1835 }, | ||
367 | { "ad1836", AD1836 }, | ||
368 | { "ad1837", AD1835 }, | ||
369 | { "ad1838", AD1838 }, | ||
370 | { "ad1839", AD1838 }, | ||
371 | { }, | ||
372 | }; | ||
373 | MODULE_DEVICE_TABLE(spi, ad1836_ids); | ||
306 | 374 | ||
307 | static struct spi_driver ad1836_spi_driver = { | 375 | static struct spi_driver ad1836_spi_driver = { |
308 | .driver = { | 376 | .driver = { |
309 | .name = "ad1836-codec", | 377 | .name = "ad1836", |
310 | .owner = THIS_MODULE, | 378 | .owner = THIS_MODULE, |
311 | }, | 379 | }, |
312 | .probe = ad1836_spi_probe, | 380 | .probe = ad1836_spi_probe, |
313 | .remove = __devexit_p(ad1836_spi_remove), | 381 | .remove = __devexit_p(ad1836_spi_remove), |
382 | .id_table = ad1836_ids, | ||
314 | }; | 383 | }; |
315 | 384 | ||
316 | static int __init ad1836_init(void) | 385 | static int __init ad1836_init(void) |
317 | { | 386 | { |
318 | int ret; | 387 | return spi_register_driver(&ad1836_spi_driver); |
319 | |||
320 | ret = spi_register_driver(&ad1836_spi_driver); | ||
321 | if (ret != 0) { | ||
322 | printk(KERN_ERR "Failed to register ad1836 SPI driver: %d\n", | ||
323 | ret); | ||
324 | } | ||
325 | |||
326 | return ret; | ||
327 | } | 388 | } |
328 | module_init(ad1836_init); | 389 | module_init(ad1836_init); |
329 | 390 | ||
diff --git a/sound/soc/codecs/ad1836.h b/sound/soc/codecs/ad1836.h index 9d6a3f8f8aaf..444747f0db26 100644 --- a/sound/soc/codecs/ad1836.h +++ b/sound/soc/codecs/ad1836.h | |||
@@ -1,19 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * File: sound/soc/codecs/ad1836.h | 2 | * Audio Codec driver supporting: |
3 | * Based on: | 3 | * AD1835A, AD1836, AD1837A, AD1838A, AD1839A |
4 | * Author: Barry Song <Barry.Song@analog.com> | ||
5 | * | 4 | * |
6 | * Created: Aug 04, 2009 | 5 | * Copyright 2009-2011 Analog Devices Inc. |
7 | * Description: definitions for AD1836 registers | ||
8 | * | 6 | * |
9 | * Modified: | 7 | * Licensed under the GPL-2 or later. |
10 | * | ||
11 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | */ | 8 | */ |
18 | 9 | ||
19 | #ifndef __AD1836_H__ | 10 | #ifndef __AD1836_H__ |
@@ -21,39 +12,30 @@ | |||
21 | 12 | ||
22 | #define AD1836_DAC_CTRL1 0 | 13 | #define AD1836_DAC_CTRL1 0 |
23 | #define AD1836_DAC_POWERDOWN 2 | 14 | #define AD1836_DAC_POWERDOWN 2 |
24 | #define AD1836_DAC_SERFMT_MASK 0xE0 | 15 | #define AD1836_DAC_SERFMT_MASK 0xE0 |
25 | #define AD1836_DAC_SERFMT_PCK256 (0x4 << 5) | 16 | #define AD1836_DAC_SERFMT_PCK256 (0x4 << 5) |
26 | #define AD1836_DAC_SERFMT_PCK128 (0x5 << 5) | 17 | #define AD1836_DAC_SERFMT_PCK128 (0x5 << 5) |
27 | #define AD1836_DAC_WORD_LEN_MASK 0x18 | 18 | #define AD1836_DAC_WORD_LEN_MASK 0x18 |
28 | #define AD1836_DAC_WORD_LEN_OFFSET 3 | 19 | #define AD1836_DAC_WORD_LEN_OFFSET 3 |
29 | 20 | ||
30 | #define AD1836_DAC_CTRL2 1 | 21 | #define AD1836_DAC_CTRL2 1 |
31 | #define AD1836_DACL1_MUTE 0 | ||
32 | #define AD1836_DACR1_MUTE 1 | ||
33 | #define AD1836_DACL2_MUTE 2 | ||
34 | #define AD1836_DACR2_MUTE 3 | ||
35 | #define AD1836_DACL3_MUTE 4 | ||
36 | #define AD1836_DACR3_MUTE 5 | ||
37 | 22 | ||
38 | #define AD1836_DAC_L1_VOL 2 | 23 | /* These macros are one-based. So AD183X_MUTE_LEFT(1) will return the mute bit |
39 | #define AD1836_DAC_R1_VOL 3 | 24 | * for the first ADC/DAC */ |
40 | #define AD1836_DAC_L2_VOL 4 | 25 | #define AD1836_MUTE_LEFT(x) (((x) * 2) - 2) |
41 | #define AD1836_DAC_R2_VOL 5 | 26 | #define AD1836_MUTE_RIGHT(x) (((x) * 2) - 1) |
42 | #define AD1836_DAC_L3_VOL 6 | 27 | |
43 | #define AD1836_DAC_R3_VOL 7 | 28 | #define AD1836_DAC_L_VOL(x) ((x) * 2) |
29 | #define AD1836_DAC_R_VOL(x) (1 + ((x) * 2)) | ||
44 | 30 | ||
45 | #define AD1836_ADC_CTRL1 12 | 31 | #define AD1836_ADC_CTRL1 12 |
46 | #define AD1836_ADC_POWERDOWN 7 | 32 | #define AD1836_ADC_POWERDOWN 7 |
47 | #define AD1836_ADC_HIGHPASS_FILTER 8 | 33 | #define AD1836_ADC_HIGHPASS_FILTER 8 |
48 | 34 | ||
49 | #define AD1836_ADC_CTRL2 13 | 35 | #define AD1836_ADC_CTRL2 13 |
50 | #define AD1836_ADCL1_MUTE 0 | ||
51 | #define AD1836_ADCR1_MUTE 1 | ||
52 | #define AD1836_ADCL2_MUTE 2 | ||
53 | #define AD1836_ADCR2_MUTE 3 | ||
54 | #define AD1836_ADC_WORD_LEN_MASK 0x30 | 36 | #define AD1836_ADC_WORD_LEN_MASK 0x30 |
55 | #define AD1836_ADC_WORD_OFFSET 5 | 37 | #define AD1836_ADC_WORD_OFFSET 5 |
56 | #define AD1836_ADC_SERFMT_MASK (7 << 6) | 38 | #define AD1836_ADC_SERFMT_MASK (7 << 6) |
57 | #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) | 39 | #define AD1836_ADC_SERFMT_PCK256 (0x4 << 6) |
58 | #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) | 40 | #define AD1836_ADC_SERFMT_PCK128 (0x5 << 6) |
59 | #define AD1836_ADC_AUX (0x6 << 6) | 41 | #define AD1836_ADC_AUX (0x6 << 6) |
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c new file mode 100644 index 000000000000..2758d5fc60d6 --- /dev/null +++ b/sound/soc/codecs/adau1701.c | |||
@@ -0,0 +1,549 @@ | |||
1 | /* | ||
2 | * Driver for ADAU1701 SigmaDSP processor | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * based on an inital version by Cliff Cai <cliff.cai@analog.com> | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/module.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/sigma.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/soc.h> | ||
21 | |||
22 | #include "adau1701.h" | ||
23 | |||
24 | #define ADAU1701_DSPCTRL 0x1c | ||
25 | #define ADAU1701_SEROCTL 0x1e | ||
26 | #define ADAU1701_SERICTL 0x1f | ||
27 | |||
28 | #define ADAU1701_AUXNPOW 0x22 | ||
29 | |||
30 | #define ADAU1701_OSCIPOW 0x26 | ||
31 | #define ADAU1701_DACSET 0x27 | ||
32 | |||
33 | #define ADAU1701_NUM_REGS 0x28 | ||
34 | |||
35 | #define ADAU1701_DSPCTRL_CR (1 << 2) | ||
36 | #define ADAU1701_DSPCTRL_DAM (1 << 3) | ||
37 | #define ADAU1701_DSPCTRL_ADM (1 << 4) | ||
38 | #define ADAU1701_DSPCTRL_SR_48 0x00 | ||
39 | #define ADAU1701_DSPCTRL_SR_96 0x01 | ||
40 | #define ADAU1701_DSPCTRL_SR_192 0x02 | ||
41 | #define ADAU1701_DSPCTRL_SR_MASK 0x03 | ||
42 | |||
43 | #define ADAU1701_SEROCTL_INV_LRCLK 0x2000 | ||
44 | #define ADAU1701_SEROCTL_INV_BCLK 0x1000 | ||
45 | #define ADAU1701_SEROCTL_MASTER 0x0800 | ||
46 | |||
47 | #define ADAU1701_SEROCTL_OBF16 0x0000 | ||
48 | #define ADAU1701_SEROCTL_OBF8 0x0200 | ||
49 | #define ADAU1701_SEROCTL_OBF4 0x0400 | ||
50 | #define ADAU1701_SEROCTL_OBF2 0x0600 | ||
51 | #define ADAU1701_SEROCTL_OBF_MASK 0x0600 | ||
52 | |||
53 | #define ADAU1701_SEROCTL_OLF1024 0x0000 | ||
54 | #define ADAU1701_SEROCTL_OLF512 0x0080 | ||
55 | #define ADAU1701_SEROCTL_OLF256 0x0100 | ||
56 | #define ADAU1701_SEROCTL_OLF_MASK 0x0180 | ||
57 | |||
58 | #define ADAU1701_SEROCTL_MSB_DEALY1 0x0000 | ||
59 | #define ADAU1701_SEROCTL_MSB_DEALY0 0x0004 | ||
60 | #define ADAU1701_SEROCTL_MSB_DEALY8 0x0008 | ||
61 | #define ADAU1701_SEROCTL_MSB_DEALY12 0x000c | ||
62 | #define ADAU1701_SEROCTL_MSB_DEALY16 0x0010 | ||
63 | #define ADAU1701_SEROCTL_MSB_DEALY_MASK 0x001c | ||
64 | |||
65 | #define ADAU1701_SEROCTL_WORD_LEN_24 0x0000 | ||
66 | #define ADAU1701_SEROCTL_WORD_LEN_20 0x0001 | ||
67 | #define ADAU1701_SEROCTL_WORD_LEN_16 0x0010 | ||
68 | #define ADAU1701_SEROCTL_WORD_LEN_MASK 0x0003 | ||
69 | |||
70 | #define ADAU1701_AUXNPOW_VBPD 0x40 | ||
71 | #define ADAU1701_AUXNPOW_VRPD 0x20 | ||
72 | |||
73 | #define ADAU1701_SERICTL_I2S 0 | ||
74 | #define ADAU1701_SERICTL_LEFTJ 1 | ||
75 | #define ADAU1701_SERICTL_TDM 2 | ||
76 | #define ADAU1701_SERICTL_RIGHTJ_24 3 | ||
77 | #define ADAU1701_SERICTL_RIGHTJ_20 4 | ||
78 | #define ADAU1701_SERICTL_RIGHTJ_18 5 | ||
79 | #define ADAU1701_SERICTL_RIGHTJ_16 6 | ||
80 | #define ADAU1701_SERICTL_MODE_MASK 7 | ||
81 | #define ADAU1701_SERICTL_INV_BCLK BIT(3) | ||
82 | #define ADAU1701_SERICTL_INV_LRCLK BIT(4) | ||
83 | |||
84 | #define ADAU1701_OSCIPOW_OPD 0x04 | ||
85 | #define ADAU1701_DACSET_DACINIT 1 | ||
86 | |||
87 | #define ADAU1701_FIRMWARE "adau1701.bin" | ||
88 | |||
89 | struct adau1701 { | ||
90 | unsigned int dai_fmt; | ||
91 | }; | ||
92 | |||
93 | static const struct snd_kcontrol_new adau1701_controls[] = { | ||
94 | SOC_SINGLE("Master Capture Switch", ADAU1701_DSPCTRL, 4, 1, 0), | ||
95 | }; | ||
96 | |||
97 | static const struct snd_soc_dapm_widget adau1701_dapm_widgets[] = { | ||
98 | SND_SOC_DAPM_DAC("DAC0", "Playback", ADAU1701_AUXNPOW, 3, 1), | ||
99 | SND_SOC_DAPM_DAC("DAC1", "Playback", ADAU1701_AUXNPOW, 2, 1), | ||
100 | SND_SOC_DAPM_DAC("DAC2", "Playback", ADAU1701_AUXNPOW, 1, 1), | ||
101 | SND_SOC_DAPM_DAC("DAC3", "Playback", ADAU1701_AUXNPOW, 0, 1), | ||
102 | SND_SOC_DAPM_ADC("ADC", "Capture", ADAU1701_AUXNPOW, 7, 1), | ||
103 | |||
104 | SND_SOC_DAPM_OUTPUT("OUT0"), | ||
105 | SND_SOC_DAPM_OUTPUT("OUT1"), | ||
106 | SND_SOC_DAPM_OUTPUT("OUT2"), | ||
107 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
108 | SND_SOC_DAPM_INPUT("IN0"), | ||
109 | SND_SOC_DAPM_INPUT("IN1"), | ||
110 | }; | ||
111 | |||
112 | static const struct snd_soc_dapm_route adau1701_dapm_routes[] = { | ||
113 | { "OUT0", NULL, "DAC0" }, | ||
114 | { "OUT1", NULL, "DAC1" }, | ||
115 | { "OUT2", NULL, "DAC2" }, | ||
116 | { "OUT3", NULL, "DAC3" }, | ||
117 | |||
118 | { "ADC", NULL, "IN0" }, | ||
119 | { "ADC", NULL, "IN1" }, | ||
120 | }; | ||
121 | |||
122 | static unsigned int adau1701_register_size(struct snd_soc_codec *codec, | ||
123 | unsigned int reg) | ||
124 | { | ||
125 | switch (reg) { | ||
126 | case ADAU1701_DSPCTRL: | ||
127 | case ADAU1701_SEROCTL: | ||
128 | case ADAU1701_AUXNPOW: | ||
129 | case ADAU1701_OSCIPOW: | ||
130 | case ADAU1701_DACSET: | ||
131 | return 2; | ||
132 | case ADAU1701_SERICTL: | ||
133 | return 1; | ||
134 | } | ||
135 | |||
136 | dev_err(codec->dev, "Unsupported register address: %d\n", reg); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, | ||
141 | unsigned int value) | ||
142 | { | ||
143 | unsigned int i; | ||
144 | unsigned int size; | ||
145 | uint8_t buf[4]; | ||
146 | int ret; | ||
147 | |||
148 | size = adau1701_register_size(codec, reg); | ||
149 | if (size == 0) | ||
150 | return -EINVAL; | ||
151 | |||
152 | snd_soc_cache_write(codec, reg, value); | ||
153 | |||
154 | buf[0] = 0x08; | ||
155 | buf[1] = reg; | ||
156 | |||
157 | for (i = size + 1; i >= 2; --i) { | ||
158 | buf[i] = value; | ||
159 | value >>= 8; | ||
160 | } | ||
161 | |||
162 | ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2); | ||
163 | if (ret == size + 2) | ||
164 | return 0; | ||
165 | else if (ret < 0) | ||
166 | return ret; | ||
167 | else | ||
168 | return -EIO; | ||
169 | } | ||
170 | |||
171 | static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) | ||
172 | { | ||
173 | unsigned int value; | ||
174 | unsigned int ret; | ||
175 | |||
176 | ret = snd_soc_cache_read(codec, reg, &value); | ||
177 | if (ret) | ||
178 | return ret; | ||
179 | |||
180 | return value; | ||
181 | } | ||
182 | |||
183 | static int adau1701_load_firmware(struct snd_soc_codec *codec) | ||
184 | { | ||
185 | return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE); | ||
186 | } | ||
187 | |||
188 | static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, | ||
189 | snd_pcm_format_t format) | ||
190 | { | ||
191 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
192 | unsigned int mask = ADAU1701_SEROCTL_WORD_LEN_MASK; | ||
193 | unsigned int val; | ||
194 | |||
195 | switch (format) { | ||
196 | case SNDRV_PCM_FORMAT_S16_LE: | ||
197 | val = ADAU1701_SEROCTL_WORD_LEN_16; | ||
198 | break; | ||
199 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
200 | val = ADAU1701_SEROCTL_WORD_LEN_20; | ||
201 | break; | ||
202 | case SNDRV_PCM_FORMAT_S24_LE: | ||
203 | val = ADAU1701_SEROCTL_WORD_LEN_24; | ||
204 | break; | ||
205 | default: | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | if (adau1701->dai_fmt == SND_SOC_DAIFMT_RIGHT_J) { | ||
210 | switch (format) { | ||
211 | case SNDRV_PCM_FORMAT_S16_LE: | ||
212 | val |= ADAU1701_SEROCTL_MSB_DEALY16; | ||
213 | break; | ||
214 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
215 | val |= ADAU1701_SEROCTL_MSB_DEALY12; | ||
216 | break; | ||
217 | case SNDRV_PCM_FORMAT_S24_LE: | ||
218 | val |= ADAU1701_SEROCTL_MSB_DEALY8; | ||
219 | break; | ||
220 | } | ||
221 | mask |= ADAU1701_SEROCTL_MSB_DEALY_MASK; | ||
222 | } | ||
223 | |||
224 | snd_soc_update_bits(codec, ADAU1701_SEROCTL, mask, val); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int adau1701_set_playback_pcm_format(struct snd_soc_codec *codec, | ||
230 | snd_pcm_format_t format) | ||
231 | { | ||
232 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
233 | unsigned int val; | ||
234 | |||
235 | if (adau1701->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) | ||
236 | return 0; | ||
237 | |||
238 | switch (format) { | ||
239 | case SNDRV_PCM_FORMAT_S16_LE: | ||
240 | val = ADAU1701_SERICTL_RIGHTJ_16; | ||
241 | break; | ||
242 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
243 | val = ADAU1701_SERICTL_RIGHTJ_20; | ||
244 | break; | ||
245 | case SNDRV_PCM_FORMAT_S24_LE: | ||
246 | val = ADAU1701_SERICTL_RIGHTJ_24; | ||
247 | break; | ||
248 | default: | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | snd_soc_update_bits(codec, ADAU1701_SERICTL, | ||
253 | ADAU1701_SERICTL_MODE_MASK, val); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int adau1701_hw_params(struct snd_pcm_substream *substream, | ||
259 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
260 | { | ||
261 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
262 | struct snd_soc_codec *codec = rtd->codec; | ||
263 | snd_pcm_format_t format; | ||
264 | unsigned int val; | ||
265 | |||
266 | switch (params_rate(params)) { | ||
267 | case 192000: | ||
268 | val = ADAU1701_DSPCTRL_SR_192; | ||
269 | break; | ||
270 | case 96000: | ||
271 | val = ADAU1701_DSPCTRL_SR_96; | ||
272 | break; | ||
273 | case 48000: | ||
274 | val = ADAU1701_DSPCTRL_SR_48; | ||
275 | break; | ||
276 | default: | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | snd_soc_update_bits(codec, ADAU1701_DSPCTRL, | ||
281 | ADAU1701_DSPCTRL_SR_MASK, val); | ||
282 | |||
283 | format = params_format(params); | ||
284 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
285 | return adau1701_set_playback_pcm_format(codec, format); | ||
286 | else | ||
287 | return adau1701_set_capture_pcm_format(codec, format); | ||
288 | } | ||
289 | |||
290 | static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
291 | unsigned int fmt) | ||
292 | { | ||
293 | struct snd_soc_codec *codec = codec_dai->codec; | ||
294 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
295 | unsigned int serictl = 0x00, seroctl = 0x00; | ||
296 | bool invert_lrclk; | ||
297 | |||
298 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
299 | case SND_SOC_DAIFMT_CBM_CFM: | ||
300 | /* master, 64-bits per sample, 1 frame per sample */ | ||
301 | seroctl |= ADAU1701_SEROCTL_MASTER | ADAU1701_SEROCTL_OBF16 | ||
302 | | ADAU1701_SEROCTL_OLF1024; | ||
303 | break; | ||
304 | case SND_SOC_DAIFMT_CBS_CFS: | ||
305 | break; | ||
306 | default: | ||
307 | return -EINVAL; | ||
308 | } | ||
309 | |||
310 | /* clock inversion */ | ||
311 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
312 | case SND_SOC_DAIFMT_NB_NF: | ||
313 | invert_lrclk = false; | ||
314 | break; | ||
315 | case SND_SOC_DAIFMT_NB_IF: | ||
316 | invert_lrclk = true; | ||
317 | break; | ||
318 | case SND_SOC_DAIFMT_IB_NF: | ||
319 | invert_lrclk = false; | ||
320 | serictl |= ADAU1701_SERICTL_INV_BCLK; | ||
321 | seroctl |= ADAU1701_SEROCTL_INV_BCLK; | ||
322 | break; | ||
323 | case SND_SOC_DAIFMT_IB_IF: | ||
324 | invert_lrclk = true; | ||
325 | serictl |= ADAU1701_SERICTL_INV_BCLK; | ||
326 | seroctl |= ADAU1701_SEROCTL_INV_BCLK; | ||
327 | break; | ||
328 | default: | ||
329 | return -EINVAL; | ||
330 | } | ||
331 | |||
332 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
333 | case SND_SOC_DAIFMT_I2S: | ||
334 | break; | ||
335 | case SND_SOC_DAIFMT_LEFT_J: | ||
336 | serictl |= ADAU1701_SERICTL_LEFTJ; | ||
337 | seroctl |= ADAU1701_SEROCTL_MSB_DEALY0; | ||
338 | invert_lrclk = !invert_lrclk; | ||
339 | break; | ||
340 | case SND_SOC_DAIFMT_RIGHT_J: | ||
341 | serictl |= ADAU1701_SERICTL_RIGHTJ_24; | ||
342 | seroctl |= ADAU1701_SEROCTL_MSB_DEALY8; | ||
343 | invert_lrclk = !invert_lrclk; | ||
344 | break; | ||
345 | default: | ||
346 | return -EINVAL; | ||
347 | } | ||
348 | |||
349 | if (invert_lrclk) { | ||
350 | seroctl |= ADAU1701_SEROCTL_INV_LRCLK; | ||
351 | serictl |= ADAU1701_SERICTL_INV_LRCLK; | ||
352 | } | ||
353 | |||
354 | adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
355 | |||
356 | snd_soc_write(codec, ADAU1701_SERICTL, serictl); | ||
357 | snd_soc_update_bits(codec, ADAU1701_SEROCTL, | ||
358 | ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int adau1701_set_bias_level(struct snd_soc_codec *codec, | ||
364 | enum snd_soc_bias_level level) | ||
365 | { | ||
366 | unsigned int mask = ADAU1701_AUXNPOW_VBPD | ADAU1701_AUXNPOW_VRPD; | ||
367 | |||
368 | switch (level) { | ||
369 | case SND_SOC_BIAS_ON: | ||
370 | break; | ||
371 | case SND_SOC_BIAS_PREPARE: | ||
372 | break; | ||
373 | case SND_SOC_BIAS_STANDBY: | ||
374 | /* Enable VREF and VREF buffer */ | ||
375 | snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, 0x00); | ||
376 | break; | ||
377 | case SND_SOC_BIAS_OFF: | ||
378 | /* Disable VREF and VREF buffer */ | ||
379 | snd_soc_update_bits(codec, ADAU1701_AUXNPOW, mask, mask); | ||
380 | break; | ||
381 | } | ||
382 | |||
383 | codec->dapm.bias_level = level; | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute) | ||
388 | { | ||
389 | struct snd_soc_codec *codec = dai->codec; | ||
390 | unsigned int mask = ADAU1701_DSPCTRL_DAM; | ||
391 | unsigned int val; | ||
392 | |||
393 | if (mute) | ||
394 | val = 0; | ||
395 | else | ||
396 | val = mask; | ||
397 | |||
398 | snd_soc_update_bits(codec, ADAU1701_DSPCTRL, mask, val); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | ||
404 | unsigned int freq, int dir) | ||
405 | { | ||
406 | unsigned int val; | ||
407 | |||
408 | switch (clk_id) { | ||
409 | case ADAU1701_CLK_SRC_OSC: | ||
410 | val = 0x0; | ||
411 | break; | ||
412 | case ADAU1701_CLK_SRC_MCLK: | ||
413 | val = ADAU1701_OSCIPOW_OPD; | ||
414 | break; | ||
415 | default: | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | |||
419 | snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ | ||
425 | SNDRV_PCM_RATE_192000) | ||
426 | |||
427 | #define ADAU1701_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
428 | SNDRV_PCM_FMTBIT_S24_LE) | ||
429 | |||
430 | static const struct snd_soc_dai_ops adau1701_dai_ops = { | ||
431 | .set_fmt = adau1701_set_dai_fmt, | ||
432 | .hw_params = adau1701_hw_params, | ||
433 | .digital_mute = adau1701_digital_mute, | ||
434 | }; | ||
435 | |||
436 | static struct snd_soc_dai_driver adau1701_dai = { | ||
437 | .name = "adau1701", | ||
438 | .playback = { | ||
439 | .stream_name = "Playback", | ||
440 | .channels_min = 2, | ||
441 | .channels_max = 8, | ||
442 | .rates = ADAU1701_RATES, | ||
443 | .formats = ADAU1701_FORMATS, | ||
444 | }, | ||
445 | .capture = { | ||
446 | .stream_name = "Capture", | ||
447 | .channels_min = 2, | ||
448 | .channels_max = 8, | ||
449 | .rates = ADAU1701_RATES, | ||
450 | .formats = ADAU1701_FORMATS, | ||
451 | }, | ||
452 | .ops = &adau1701_dai_ops, | ||
453 | .symmetric_rates = 1, | ||
454 | }; | ||
455 | |||
456 | static int adau1701_probe(struct snd_soc_codec *codec) | ||
457 | { | ||
458 | int ret; | ||
459 | |||
460 | codec->dapm.idle_bias_off = 1; | ||
461 | |||
462 | ret = adau1701_load_firmware(codec); | ||
463 | if (ret) | ||
464 | dev_warn(codec->dev, "Failed to load firmware\n"); | ||
465 | |||
466 | snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); | ||
467 | snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); | ||
468 | |||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | static struct snd_soc_codec_driver adau1701_codec_drv = { | ||
473 | .probe = adau1701_probe, | ||
474 | .set_bias_level = adau1701_set_bias_level, | ||
475 | |||
476 | .reg_cache_size = ADAU1701_NUM_REGS, | ||
477 | .reg_word_size = sizeof(u16), | ||
478 | |||
479 | .controls = adau1701_controls, | ||
480 | .num_controls = ARRAY_SIZE(adau1701_controls), | ||
481 | .dapm_widgets = adau1701_dapm_widgets, | ||
482 | .num_dapm_widgets = ARRAY_SIZE(adau1701_dapm_widgets), | ||
483 | .dapm_routes = adau1701_dapm_routes, | ||
484 | .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), | ||
485 | |||
486 | .write = adau1701_write, | ||
487 | .read = adau1701_read, | ||
488 | |||
489 | .set_sysclk = adau1701_set_sysclk, | ||
490 | }; | ||
491 | |||
492 | static __devinit int adau1701_i2c_probe(struct i2c_client *client, | ||
493 | const struct i2c_device_id *id) | ||
494 | { | ||
495 | struct adau1701 *adau1701; | ||
496 | int ret; | ||
497 | |||
498 | adau1701 = kzalloc(sizeof(*adau1701), GFP_KERNEL); | ||
499 | if (!adau1701) | ||
500 | return -ENOMEM; | ||
501 | |||
502 | i2c_set_clientdata(client, adau1701); | ||
503 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, | ||
504 | &adau1701_dai, 1); | ||
505 | if (ret < 0) | ||
506 | kfree(adau1701); | ||
507 | |||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | static __devexit int adau1701_i2c_remove(struct i2c_client *client) | ||
512 | { | ||
513 | snd_soc_unregister_codec(&client->dev); | ||
514 | kfree(i2c_get_clientdata(client)); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static const struct i2c_device_id adau1701_i2c_id[] = { | ||
519 | { "adau1701", 0 }, | ||
520 | { } | ||
521 | }; | ||
522 | MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); | ||
523 | |||
524 | static struct i2c_driver adau1701_i2c_driver = { | ||
525 | .driver = { | ||
526 | .name = "adau1701", | ||
527 | .owner = THIS_MODULE, | ||
528 | }, | ||
529 | .probe = adau1701_i2c_probe, | ||
530 | .remove = __devexit_p(adau1701_i2c_remove), | ||
531 | .id_table = adau1701_i2c_id, | ||
532 | }; | ||
533 | |||
534 | static int __init adau1701_init(void) | ||
535 | { | ||
536 | return i2c_add_driver(&adau1701_i2c_driver); | ||
537 | } | ||
538 | module_init(adau1701_init); | ||
539 | |||
540 | static void __exit adau1701_exit(void) | ||
541 | { | ||
542 | i2c_del_driver(&adau1701_i2c_driver); | ||
543 | } | ||
544 | module_exit(adau1701_exit); | ||
545 | |||
546 | MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver"); | ||
547 | MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>"); | ||
548 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
549 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1701.h b/sound/soc/codecs/adau1701.h new file mode 100644 index 000000000000..8d0949a2aec9 --- /dev/null +++ b/sound/soc/codecs/adau1701.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * header file for ADAU1701 SigmaDSP processor | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #ifndef _ADAU1701_H | ||
10 | #define _ADAU1701_H | ||
11 | |||
12 | enum adau1701_clk_src { | ||
13 | ADAU1701_CLK_SRC_OSC, | ||
14 | ADAU1701_CLK_SRC_MCLK, | ||
15 | }; | ||
16 | |||
17 | #endif | ||
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c new file mode 100644 index 000000000000..e30fba62392d --- /dev/null +++ b/sound/soc/codecs/adav80x.c | |||
@@ -0,0 +1,951 @@ | |||
1 | /* | ||
2 | * ADAV80X Audio Codec driver supporting ADAV801, ADAV803 | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * Author: Yi Li <yi.li@analog.com> | ||
6 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
7 | * | ||
8 | * Licensed under the GPL-2 or later. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/tlv.h> | ||
21 | #include <sound/soc.h> | ||
22 | |||
23 | #include "adav80x.h" | ||
24 | |||
25 | #define ADAV80X_PLAYBACK_CTRL 0x04 | ||
26 | #define ADAV80X_AUX_IN_CTRL 0x05 | ||
27 | #define ADAV80X_REC_CTRL 0x06 | ||
28 | #define ADAV80X_AUX_OUT_CTRL 0x07 | ||
29 | #define ADAV80X_DPATH_CTRL1 0x62 | ||
30 | #define ADAV80X_DPATH_CTRL2 0x63 | ||
31 | #define ADAV80X_DAC_CTRL1 0x64 | ||
32 | #define ADAV80X_DAC_CTRL2 0x65 | ||
33 | #define ADAV80X_DAC_CTRL3 0x66 | ||
34 | #define ADAV80X_DAC_L_VOL 0x68 | ||
35 | #define ADAV80X_DAC_R_VOL 0x69 | ||
36 | #define ADAV80X_PGA_L_VOL 0x6c | ||
37 | #define ADAV80X_PGA_R_VOL 0x6d | ||
38 | #define ADAV80X_ADC_CTRL1 0x6e | ||
39 | #define ADAV80X_ADC_CTRL2 0x6f | ||
40 | #define ADAV80X_ADC_L_VOL 0x70 | ||
41 | #define ADAV80X_ADC_R_VOL 0x71 | ||
42 | #define ADAV80X_PLL_CTRL1 0x74 | ||
43 | #define ADAV80X_PLL_CTRL2 0x75 | ||
44 | #define ADAV80X_ICLK_CTRL1 0x76 | ||
45 | #define ADAV80X_ICLK_CTRL2 0x77 | ||
46 | #define ADAV80X_PLL_CLK_SRC 0x78 | ||
47 | #define ADAV80X_PLL_OUTE 0x7a | ||
48 | |||
49 | #define ADAV80X_PLL_CLK_SRC_PLL_XIN(pll) 0x00 | ||
50 | #define ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll) (0x40 << (pll)) | ||
51 | #define ADAV80X_PLL_CLK_SRC_PLL_MASK(pll) (0x40 << (pll)) | ||
52 | |||
53 | #define ADAV80X_ICLK_CTRL1_DAC_SRC(src) ((src) << 5) | ||
54 | #define ADAV80X_ICLK_CTRL1_ADC_SRC(src) ((src) << 2) | ||
55 | #define ADAV80X_ICLK_CTRL1_ICLK2_SRC(src) (src) | ||
56 | #define ADAV80X_ICLK_CTRL2_ICLK1_SRC(src) ((src) << 3) | ||
57 | |||
58 | #define ADAV80X_PLL_CTRL1_PLLDIV 0x10 | ||
59 | #define ADAV80X_PLL_CTRL1_PLLPD(pll) (0x04 << (pll)) | ||
60 | #define ADAV80X_PLL_CTRL1_XTLPD 0x02 | ||
61 | |||
62 | #define ADAV80X_PLL_CTRL2_FIELD(pll, x) ((x) << ((pll) * 4)) | ||
63 | |||
64 | #define ADAV80X_PLL_CTRL2_FS_48(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x00) | ||
65 | #define ADAV80X_PLL_CTRL2_FS_32(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x08) | ||
66 | #define ADAV80X_PLL_CTRL2_FS_44(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0c) | ||
67 | |||
68 | #define ADAV80X_PLL_CTRL2_SEL(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x02) | ||
69 | #define ADAV80X_PLL_CTRL2_DOUB(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x01) | ||
70 | #define ADAV80X_PLL_CTRL2_PLL_MASK(pll) ADAV80X_PLL_CTRL2_FIELD((pll), 0x0f) | ||
71 | |||
72 | #define ADAV80X_ADC_CTRL1_MODULATOR_MASK 0x80 | ||
73 | #define ADAV80X_ADC_CTRL1_MODULATOR_128FS 0x00 | ||
74 | #define ADAV80X_ADC_CTRL1_MODULATOR_64FS 0x80 | ||
75 | |||
76 | #define ADAV80X_DAC_CTRL1_PD 0x80 | ||
77 | |||
78 | #define ADAV80X_DAC_CTRL2_DIV1 0x00 | ||
79 | #define ADAV80X_DAC_CTRL2_DIV1_5 0x10 | ||
80 | #define ADAV80X_DAC_CTRL2_DIV2 0x20 | ||
81 | #define ADAV80X_DAC_CTRL2_DIV3 0x30 | ||
82 | #define ADAV80X_DAC_CTRL2_DIV_MASK 0x30 | ||
83 | |||
84 | #define ADAV80X_DAC_CTRL2_INTERPOL_256FS 0x00 | ||
85 | #define ADAV80X_DAC_CTRL2_INTERPOL_128FS 0x40 | ||
86 | #define ADAV80X_DAC_CTRL2_INTERPOL_64FS 0x80 | ||
87 | #define ADAV80X_DAC_CTRL2_INTERPOL_MASK 0xc0 | ||
88 | |||
89 | #define ADAV80X_DAC_CTRL2_DEEMPH_NONE 0x00 | ||
90 | #define ADAV80X_DAC_CTRL2_DEEMPH_44 0x01 | ||
91 | #define ADAV80X_DAC_CTRL2_DEEMPH_32 0x02 | ||
92 | #define ADAV80X_DAC_CTRL2_DEEMPH_48 0x03 | ||
93 | #define ADAV80X_DAC_CTRL2_DEEMPH_MASK 0x01 | ||
94 | |||
95 | #define ADAV80X_CAPTURE_MODE_MASTER 0x20 | ||
96 | #define ADAV80X_CAPTURE_WORD_LEN24 0x00 | ||
97 | #define ADAV80X_CAPTURE_WORD_LEN20 0x04 | ||
98 | #define ADAV80X_CAPTRUE_WORD_LEN18 0x08 | ||
99 | #define ADAV80X_CAPTURE_WORD_LEN16 0x0c | ||
100 | #define ADAV80X_CAPTURE_WORD_LEN_MASK 0x0c | ||
101 | |||
102 | #define ADAV80X_CAPTURE_MODE_LEFT_J 0x00 | ||
103 | #define ADAV80X_CAPTURE_MODE_I2S 0x01 | ||
104 | #define ADAV80X_CAPTURE_MODE_RIGHT_J 0x03 | ||
105 | #define ADAV80X_CAPTURE_MODE_MASK 0x03 | ||
106 | |||
107 | #define ADAV80X_PLAYBACK_MODE_MASTER 0x10 | ||
108 | #define ADAV80X_PLAYBACK_MODE_LEFT_J 0x00 | ||
109 | #define ADAV80X_PLAYBACK_MODE_I2S 0x01 | ||
110 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_24 0x04 | ||
111 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_20 0x05 | ||
112 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_18 0x06 | ||
113 | #define ADAV80X_PLAYBACK_MODE_RIGHT_J_16 0x07 | ||
114 | #define ADAV80X_PLAYBACK_MODE_MASK 0x07 | ||
115 | |||
116 | #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) | ||
117 | |||
118 | static u8 adav80x_default_regs[] = { | ||
119 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x01, 0x80, 0x26, 0x00, 0x00, | ||
120 | 0x02, 0x40, 0x20, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
121 | 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x92, 0xb1, 0x37, | ||
122 | 0x48, 0xd2, 0xfb, 0xca, 0xd2, 0x15, 0xe8, 0x29, 0xb9, 0x6a, 0xda, 0x2b, | ||
123 | 0xb7, 0xc0, 0x11, 0x65, 0x5c, 0xf6, 0xff, 0x8d, 0x00, 0x00, 0x00, 0x00, | ||
124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, | ||
126 | 0x00, 0xe8, 0x46, 0xe1, 0x5b, 0xd3, 0x43, 0x77, 0x93, 0xa7, 0x44, 0xee, | ||
127 | 0x32, 0x12, 0xc0, 0x11, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x3f, | ||
128 | 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, | ||
129 | 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, | ||
130 | }; | ||
131 | |||
132 | struct adav80x { | ||
133 | enum snd_soc_control_type control_type; | ||
134 | |||
135 | enum adav80x_clk_src clk_src; | ||
136 | unsigned int sysclk; | ||
137 | enum adav80x_pll_src pll_src; | ||
138 | |||
139 | unsigned int dai_fmt[2]; | ||
140 | unsigned int rate; | ||
141 | bool deemph; | ||
142 | bool sysclk_pd[3]; | ||
143 | }; | ||
144 | |||
145 | static const char *adav80x_mux_text[] = { | ||
146 | "ADC", | ||
147 | "Playback", | ||
148 | "Aux Playback", | ||
149 | }; | ||
150 | |||
151 | static const unsigned int adav80x_mux_values[] = { | ||
152 | 0, 2, 3, | ||
153 | }; | ||
154 | |||
155 | #define ADAV80X_MUX_ENUM_DECL(name, reg, shift) \ | ||
156 | SOC_VALUE_ENUM_DOUBLE_DECL(name, reg, shift, 7, \ | ||
157 | ARRAY_SIZE(adav80x_mux_text), adav80x_mux_text, \ | ||
158 | adav80x_mux_values) | ||
159 | |||
160 | static ADAV80X_MUX_ENUM_DECL(adav80x_aux_capture_enum, ADAV80X_DPATH_CTRL1, 0); | ||
161 | static ADAV80X_MUX_ENUM_DECL(adav80x_capture_enum, ADAV80X_DPATH_CTRL1, 3); | ||
162 | static ADAV80X_MUX_ENUM_DECL(adav80x_dac_enum, ADAV80X_DPATH_CTRL2, 3); | ||
163 | |||
164 | static const struct snd_kcontrol_new adav80x_aux_capture_mux_ctrl = | ||
165 | SOC_DAPM_VALUE_ENUM("Route", adav80x_aux_capture_enum); | ||
166 | static const struct snd_kcontrol_new adav80x_capture_mux_ctrl = | ||
167 | SOC_DAPM_VALUE_ENUM("Route", adav80x_capture_enum); | ||
168 | static const struct snd_kcontrol_new adav80x_dac_mux_ctrl = | ||
169 | SOC_DAPM_VALUE_ENUM("Route", adav80x_dac_enum); | ||
170 | |||
171 | #define ADAV80X_MUX(name, ctrl) \ | ||
172 | SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) | ||
173 | |||
174 | static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { | ||
175 | SND_SOC_DAPM_DAC("DAC", NULL, ADAV80X_DAC_CTRL1, 7, 1), | ||
176 | SND_SOC_DAPM_ADC("ADC", NULL, ADAV80X_ADC_CTRL1, 5, 1), | ||
177 | |||
178 | SND_SOC_DAPM_PGA("Right PGA", ADAV80X_ADC_CTRL1, 0, 1, NULL, 0), | ||
179 | SND_SOC_DAPM_PGA("Left PGA", ADAV80X_ADC_CTRL1, 1, 1, NULL, 0), | ||
180 | |||
181 | SND_SOC_DAPM_AIF_OUT("AIFOUT", "HiFi Capture", 0, SND_SOC_NOPM, 0, 0), | ||
182 | SND_SOC_DAPM_AIF_IN("AIFIN", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0), | ||
183 | |||
184 | SND_SOC_DAPM_AIF_OUT("AIFAUXOUT", "Aux Capture", 0, SND_SOC_NOPM, 0, 0), | ||
185 | SND_SOC_DAPM_AIF_IN("AIFAUXIN", "Aux Playback", 0, SND_SOC_NOPM, 0, 0), | ||
186 | |||
187 | ADAV80X_MUX("Aux Capture Select", &adav80x_aux_capture_mux_ctrl), | ||
188 | ADAV80X_MUX("Capture Select", &adav80x_capture_mux_ctrl), | ||
189 | ADAV80X_MUX("DAC Select", &adav80x_dac_mux_ctrl), | ||
190 | |||
191 | SND_SOC_DAPM_INPUT("VINR"), | ||
192 | SND_SOC_DAPM_INPUT("VINL"), | ||
193 | SND_SOC_DAPM_OUTPUT("VOUTR"), | ||
194 | SND_SOC_DAPM_OUTPUT("VOUTL"), | ||
195 | |||
196 | SND_SOC_DAPM_SUPPLY("SYSCLK", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
197 | SND_SOC_DAPM_SUPPLY("PLL1", ADAV80X_PLL_CTRL1, 2, 1, NULL, 0), | ||
198 | SND_SOC_DAPM_SUPPLY("PLL2", ADAV80X_PLL_CTRL1, 3, 1, NULL, 0), | ||
199 | SND_SOC_DAPM_SUPPLY("OSC", ADAV80X_PLL_CTRL1, 1, 1, NULL, 0), | ||
200 | }; | ||
201 | |||
202 | static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, | ||
203 | struct snd_soc_dapm_widget *sink) | ||
204 | { | ||
205 | struct snd_soc_codec *codec = source->codec; | ||
206 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
207 | const char *clk; | ||
208 | |||
209 | switch (adav80x->clk_src) { | ||
210 | case ADAV80X_CLK_PLL1: | ||
211 | clk = "PLL1"; | ||
212 | break; | ||
213 | case ADAV80X_CLK_PLL2: | ||
214 | clk = "PLL2"; | ||
215 | break; | ||
216 | case ADAV80X_CLK_XTAL: | ||
217 | clk = "OSC"; | ||
218 | break; | ||
219 | default: | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | return strcmp(source->name, clk) == 0; | ||
224 | } | ||
225 | |||
226 | static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, | ||
227 | struct snd_soc_dapm_widget *sink) | ||
228 | { | ||
229 | struct snd_soc_codec *codec = source->codec; | ||
230 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
231 | |||
232 | return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; | ||
233 | } | ||
234 | |||
235 | |||
236 | static const struct snd_soc_dapm_route adav80x_dapm_routes[] = { | ||
237 | { "DAC Select", "ADC", "ADC" }, | ||
238 | { "DAC Select", "Playback", "AIFIN" }, | ||
239 | { "DAC Select", "Aux Playback", "AIFAUXIN" }, | ||
240 | { "DAC", NULL, "DAC Select" }, | ||
241 | |||
242 | { "Capture Select", "ADC", "ADC" }, | ||
243 | { "Capture Select", "Playback", "AIFIN" }, | ||
244 | { "Capture Select", "Aux Playback", "AIFAUXIN" }, | ||
245 | { "AIFOUT", NULL, "Capture Select" }, | ||
246 | |||
247 | { "Aux Capture Select", "ADC", "ADC" }, | ||
248 | { "Aux Capture Select", "Playback", "AIFIN" }, | ||
249 | { "Aux Capture Select", "Aux Playback", "AIFAUXIN" }, | ||
250 | { "AIFAUXOUT", NULL, "Aux Capture Select" }, | ||
251 | |||
252 | { "VOUTR", NULL, "DAC" }, | ||
253 | { "VOUTL", NULL, "DAC" }, | ||
254 | |||
255 | { "Left PGA", NULL, "VINL" }, | ||
256 | { "Right PGA", NULL, "VINR" }, | ||
257 | { "ADC", NULL, "Left PGA" }, | ||
258 | { "ADC", NULL, "Right PGA" }, | ||
259 | |||
260 | { "SYSCLK", NULL, "PLL1", adav80x_dapm_sysclk_check }, | ||
261 | { "SYSCLK", NULL, "PLL2", adav80x_dapm_sysclk_check }, | ||
262 | { "SYSCLK", NULL, "OSC", adav80x_dapm_sysclk_check }, | ||
263 | { "PLL1", NULL, "OSC", adav80x_dapm_pll_check }, | ||
264 | { "PLL2", NULL, "OSC", adav80x_dapm_pll_check }, | ||
265 | |||
266 | { "ADC", NULL, "SYSCLK" }, | ||
267 | { "DAC", NULL, "SYSCLK" }, | ||
268 | { "AIFOUT", NULL, "SYSCLK" }, | ||
269 | { "AIFAUXOUT", NULL, "SYSCLK" }, | ||
270 | { "AIFIN", NULL, "SYSCLK" }, | ||
271 | { "AIFAUXIN", NULL, "SYSCLK" }, | ||
272 | }; | ||
273 | |||
274 | static int adav80x_set_deemph(struct snd_soc_codec *codec) | ||
275 | { | ||
276 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
277 | unsigned int val; | ||
278 | |||
279 | if (adav80x->deemph) { | ||
280 | switch (adav80x->rate) { | ||
281 | case 32000: | ||
282 | val = ADAV80X_DAC_CTRL2_DEEMPH_32; | ||
283 | break; | ||
284 | case 44100: | ||
285 | val = ADAV80X_DAC_CTRL2_DEEMPH_44; | ||
286 | break; | ||
287 | case 48000: | ||
288 | case 64000: | ||
289 | case 88200: | ||
290 | case 96000: | ||
291 | val = ADAV80X_DAC_CTRL2_DEEMPH_48; | ||
292 | break; | ||
293 | default: | ||
294 | val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; | ||
295 | break; | ||
296 | } | ||
297 | } else { | ||
298 | val = ADAV80X_DAC_CTRL2_DEEMPH_NONE; | ||
299 | } | ||
300 | |||
301 | return snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, | ||
302 | ADAV80X_DAC_CTRL2_DEEMPH_MASK, val); | ||
303 | } | ||
304 | |||
305 | static int adav80x_put_deemph(struct snd_kcontrol *kcontrol, | ||
306 | struct snd_ctl_elem_value *ucontrol) | ||
307 | { | ||
308 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
309 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
310 | unsigned int deemph = ucontrol->value.enumerated.item[0]; | ||
311 | |||
312 | if (deemph > 1) | ||
313 | return -EINVAL; | ||
314 | |||
315 | adav80x->deemph = deemph; | ||
316 | |||
317 | return adav80x_set_deemph(codec); | ||
318 | } | ||
319 | |||
320 | static int adav80x_get_deemph(struct snd_kcontrol *kcontrol, | ||
321 | struct snd_ctl_elem_value *ucontrol) | ||
322 | { | ||
323 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
324 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
325 | |||
326 | ucontrol->value.enumerated.item[0] = adav80x->deemph; | ||
327 | return 0; | ||
328 | }; | ||
329 | |||
330 | static const DECLARE_TLV_DB_SCALE(adav80x_inpga_tlv, 0, 50, 0); | ||
331 | static const DECLARE_TLV_DB_MINMAX(adav80x_digital_tlv, -9563, 0); | ||
332 | |||
333 | static const struct snd_kcontrol_new adav80x_controls[] = { | ||
334 | SOC_DOUBLE_R_TLV("Master Playback Volume", ADAV80X_DAC_L_VOL, | ||
335 | ADAV80X_DAC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), | ||
336 | SOC_DOUBLE_R_TLV("Master Capture Volume", ADAV80X_ADC_L_VOL, | ||
337 | ADAV80X_ADC_R_VOL, 0, 0xff, 0, adav80x_digital_tlv), | ||
338 | |||
339 | SOC_DOUBLE_R_TLV("PGA Capture Volume", ADAV80X_PGA_L_VOL, | ||
340 | ADAV80X_PGA_R_VOL, 0, 0x30, 0, adav80x_inpga_tlv), | ||
341 | |||
342 | SOC_DOUBLE("Master Playback Switch", ADAV80X_DAC_CTRL1, 0, 1, 1, 0), | ||
343 | SOC_DOUBLE("Master Capture Switch", ADAV80X_ADC_CTRL1, 2, 3, 1, 1), | ||
344 | |||
345 | SOC_SINGLE("ADC High Pass Filter Switch", ADAV80X_ADC_CTRL1, 6, 1, 0), | ||
346 | |||
347 | SOC_SINGLE_BOOL_EXT("Playback De-emphasis Switch", 0, | ||
348 | adav80x_get_deemph, adav80x_put_deemph), | ||
349 | }; | ||
350 | |||
351 | static unsigned int adav80x_port_ctrl_regs[2][2] = { | ||
352 | { ADAV80X_REC_CTRL, ADAV80X_PLAYBACK_CTRL, }, | ||
353 | { ADAV80X_AUX_OUT_CTRL, ADAV80X_AUX_IN_CTRL }, | ||
354 | }; | ||
355 | |||
356 | static int adav80x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
357 | { | ||
358 | struct snd_soc_codec *codec = dai->codec; | ||
359 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
360 | unsigned int capture = 0x00; | ||
361 | unsigned int playback = 0x00; | ||
362 | |||
363 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
364 | case SND_SOC_DAIFMT_CBM_CFM: | ||
365 | capture |= ADAV80X_CAPTURE_MODE_MASTER; | ||
366 | playback |= ADAV80X_PLAYBACK_MODE_MASTER; | ||
367 | case SND_SOC_DAIFMT_CBS_CFS: | ||
368 | break; | ||
369 | default: | ||
370 | return -EINVAL; | ||
371 | } | ||
372 | |||
373 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
374 | case SND_SOC_DAIFMT_I2S: | ||
375 | capture |= ADAV80X_CAPTURE_MODE_I2S; | ||
376 | playback |= ADAV80X_PLAYBACK_MODE_I2S; | ||
377 | break; | ||
378 | case SND_SOC_DAIFMT_LEFT_J: | ||
379 | capture |= ADAV80X_CAPTURE_MODE_LEFT_J; | ||
380 | playback |= ADAV80X_PLAYBACK_MODE_LEFT_J; | ||
381 | break; | ||
382 | case SND_SOC_DAIFMT_RIGHT_J: | ||
383 | capture |= ADAV80X_CAPTURE_MODE_RIGHT_J; | ||
384 | playback |= ADAV80X_PLAYBACK_MODE_RIGHT_J_24; | ||
385 | break; | ||
386 | default: | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
391 | case SND_SOC_DAIFMT_NB_NF: | ||
392 | break; | ||
393 | default: | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], | ||
398 | ADAV80X_CAPTURE_MODE_MASK | ADAV80X_CAPTURE_MODE_MASTER, | ||
399 | capture); | ||
400 | snd_soc_write(codec, adav80x_port_ctrl_regs[dai->id][1], playback); | ||
401 | |||
402 | adav80x->dai_fmt[dai->id] = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int adav80x_set_adc_clock(struct snd_soc_codec *codec, | ||
408 | unsigned int sample_rate) | ||
409 | { | ||
410 | unsigned int val; | ||
411 | |||
412 | if (sample_rate <= 48000) | ||
413 | val = ADAV80X_ADC_CTRL1_MODULATOR_128FS; | ||
414 | else | ||
415 | val = ADAV80X_ADC_CTRL1_MODULATOR_64FS; | ||
416 | |||
417 | snd_soc_update_bits(codec, ADAV80X_ADC_CTRL1, | ||
418 | ADAV80X_ADC_CTRL1_MODULATOR_MASK, val); | ||
419 | |||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int adav80x_set_dac_clock(struct snd_soc_codec *codec, | ||
424 | unsigned int sample_rate) | ||
425 | { | ||
426 | unsigned int val; | ||
427 | |||
428 | if (sample_rate <= 48000) | ||
429 | val = ADAV80X_DAC_CTRL2_DIV1 | ADAV80X_DAC_CTRL2_INTERPOL_256FS; | ||
430 | else | ||
431 | val = ADAV80X_DAC_CTRL2_DIV2 | ADAV80X_DAC_CTRL2_INTERPOL_128FS; | ||
432 | |||
433 | snd_soc_update_bits(codec, ADAV80X_DAC_CTRL2, | ||
434 | ADAV80X_DAC_CTRL2_DIV_MASK | ADAV80X_DAC_CTRL2_INTERPOL_MASK, | ||
435 | val); | ||
436 | |||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int adav80x_set_capture_pcm_format(struct snd_soc_codec *codec, | ||
441 | struct snd_soc_dai *dai, snd_pcm_format_t format) | ||
442 | { | ||
443 | unsigned int val; | ||
444 | |||
445 | switch (format) { | ||
446 | case SNDRV_PCM_FORMAT_S16_LE: | ||
447 | val = ADAV80X_CAPTURE_WORD_LEN16; | ||
448 | break; | ||
449 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
450 | val = ADAV80X_CAPTRUE_WORD_LEN18; | ||
451 | break; | ||
452 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
453 | val = ADAV80X_CAPTURE_WORD_LEN20; | ||
454 | break; | ||
455 | case SNDRV_PCM_FORMAT_S24_LE: | ||
456 | val = ADAV80X_CAPTURE_WORD_LEN24; | ||
457 | break; | ||
458 | default: | ||
459 | break; | ||
460 | } | ||
461 | |||
462 | snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][0], | ||
463 | ADAV80X_CAPTURE_WORD_LEN_MASK, val); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int adav80x_set_playback_pcm_format(struct snd_soc_codec *codec, | ||
469 | struct snd_soc_dai *dai, snd_pcm_format_t format) | ||
470 | { | ||
471 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
472 | unsigned int val; | ||
473 | |||
474 | if (adav80x->dai_fmt[dai->id] != SND_SOC_DAIFMT_RIGHT_J) | ||
475 | return 0; | ||
476 | |||
477 | switch (format) { | ||
478 | case SNDRV_PCM_FORMAT_S16_LE: | ||
479 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_16; | ||
480 | break; | ||
481 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
482 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_18; | ||
483 | break; | ||
484 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
485 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_20; | ||
486 | break; | ||
487 | case SNDRV_PCM_FORMAT_S24_LE: | ||
488 | val = ADAV80X_PLAYBACK_MODE_RIGHT_J_24; | ||
489 | break; | ||
490 | default: | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | snd_soc_update_bits(codec, adav80x_port_ctrl_regs[dai->id][1], | ||
495 | ADAV80X_PLAYBACK_MODE_MASK, val); | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | static int adav80x_hw_params(struct snd_pcm_substream *substream, | ||
501 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
502 | { | ||
503 | struct snd_soc_codec *codec = dai->codec; | ||
504 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
505 | unsigned int rate = params_rate(params); | ||
506 | |||
507 | if (rate * 256 != adav80x->sysclk) | ||
508 | return -EINVAL; | ||
509 | |||
510 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
511 | adav80x_set_playback_pcm_format(codec, dai, | ||
512 | params_format(params)); | ||
513 | adav80x_set_dac_clock(codec, rate); | ||
514 | } else { | ||
515 | adav80x_set_capture_pcm_format(codec, dai, | ||
516 | params_format(params)); | ||
517 | adav80x_set_adc_clock(codec, rate); | ||
518 | } | ||
519 | adav80x->rate = rate; | ||
520 | adav80x_set_deemph(codec); | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int adav80x_set_sysclk(struct snd_soc_codec *codec, | ||
526 | int clk_id, unsigned int freq, int dir) | ||
527 | { | ||
528 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
529 | |||
530 | if (dir == SND_SOC_CLOCK_IN) { | ||
531 | switch (clk_id) { | ||
532 | case ADAV80X_CLK_XIN: | ||
533 | case ADAV80X_CLK_XTAL: | ||
534 | case ADAV80X_CLK_MCLKI: | ||
535 | case ADAV80X_CLK_PLL1: | ||
536 | case ADAV80X_CLK_PLL2: | ||
537 | break; | ||
538 | default: | ||
539 | return -EINVAL; | ||
540 | } | ||
541 | |||
542 | adav80x->sysclk = freq; | ||
543 | |||
544 | if (adav80x->clk_src != clk_id) { | ||
545 | unsigned int iclk_ctrl1, iclk_ctrl2; | ||
546 | |||
547 | adav80x->clk_src = clk_id; | ||
548 | if (clk_id == ADAV80X_CLK_XTAL) | ||
549 | clk_id = ADAV80X_CLK_XIN; | ||
550 | |||
551 | iclk_ctrl1 = ADAV80X_ICLK_CTRL1_DAC_SRC(clk_id) | | ||
552 | ADAV80X_ICLK_CTRL1_ADC_SRC(clk_id) | | ||
553 | ADAV80X_ICLK_CTRL1_ICLK2_SRC(clk_id); | ||
554 | iclk_ctrl2 = ADAV80X_ICLK_CTRL2_ICLK1_SRC(clk_id); | ||
555 | |||
556 | snd_soc_write(codec, ADAV80X_ICLK_CTRL1, iclk_ctrl1); | ||
557 | snd_soc_write(codec, ADAV80X_ICLK_CTRL2, iclk_ctrl2); | ||
558 | |||
559 | snd_soc_dapm_sync(&codec->dapm); | ||
560 | } | ||
561 | } else { | ||
562 | unsigned int mask; | ||
563 | |||
564 | switch (clk_id) { | ||
565 | case ADAV80X_CLK_SYSCLK1: | ||
566 | case ADAV80X_CLK_SYSCLK2: | ||
567 | case ADAV80X_CLK_SYSCLK3: | ||
568 | break; | ||
569 | default: | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | clk_id -= ADAV80X_CLK_SYSCLK1; | ||
574 | mask = ADAV80X_PLL_OUTE_SYSCLKPD(clk_id); | ||
575 | |||
576 | if (freq == 0) { | ||
577 | snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, mask); | ||
578 | adav80x->sysclk_pd[clk_id] = true; | ||
579 | } else { | ||
580 | snd_soc_update_bits(codec, ADAV80X_PLL_OUTE, mask, 0); | ||
581 | adav80x->sysclk_pd[clk_id] = false; | ||
582 | } | ||
583 | |||
584 | if (adav80x->sysclk_pd[0]) | ||
585 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); | ||
586 | else | ||
587 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | ||
588 | |||
589 | if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) | ||
590 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); | ||
591 | else | ||
592 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | ||
593 | |||
594 | snd_soc_dapm_sync(&codec->dapm); | ||
595 | } | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int adav80x_set_pll(struct snd_soc_codec *codec, int pll_id, | ||
601 | int source, unsigned int freq_in, unsigned int freq_out) | ||
602 | { | ||
603 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
604 | unsigned int pll_ctrl1 = 0; | ||
605 | unsigned int pll_ctrl2 = 0; | ||
606 | unsigned int pll_src; | ||
607 | |||
608 | switch (source) { | ||
609 | case ADAV80X_PLL_SRC_XTAL: | ||
610 | case ADAV80X_PLL_SRC_XIN: | ||
611 | case ADAV80X_PLL_SRC_MCLKI: | ||
612 | break; | ||
613 | default: | ||
614 | return -EINVAL; | ||
615 | } | ||
616 | |||
617 | if (!freq_out) | ||
618 | return 0; | ||
619 | |||
620 | switch (freq_in) { | ||
621 | case 27000000: | ||
622 | break; | ||
623 | case 54000000: | ||
624 | if (source == ADAV80X_PLL_SRC_XIN) { | ||
625 | pll_ctrl1 |= ADAV80X_PLL_CTRL1_PLLDIV; | ||
626 | break; | ||
627 | } | ||
628 | default: | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | |||
632 | if (freq_out > 12288000) { | ||
633 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_DOUB(pll_id); | ||
634 | freq_out /= 2; | ||
635 | } | ||
636 | |||
637 | /* freq_out = sample_rate * 256 */ | ||
638 | switch (freq_out) { | ||
639 | case 8192000: | ||
640 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_32(pll_id); | ||
641 | break; | ||
642 | case 11289600: | ||
643 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_44(pll_id); | ||
644 | break; | ||
645 | case 12288000: | ||
646 | pll_ctrl2 |= ADAV80X_PLL_CTRL2_FS_48(pll_id); | ||
647 | break; | ||
648 | default: | ||
649 | return -EINVAL; | ||
650 | } | ||
651 | |||
652 | snd_soc_update_bits(codec, ADAV80X_PLL_CTRL1, ADAV80X_PLL_CTRL1_PLLDIV, | ||
653 | pll_ctrl1); | ||
654 | snd_soc_update_bits(codec, ADAV80X_PLL_CTRL2, | ||
655 | ADAV80X_PLL_CTRL2_PLL_MASK(pll_id), pll_ctrl2); | ||
656 | |||
657 | if (source != adav80x->pll_src) { | ||
658 | if (source == ADAV80X_PLL_SRC_MCLKI) | ||
659 | pll_src = ADAV80X_PLL_CLK_SRC_PLL_MCLKI(pll_id); | ||
660 | else | ||
661 | pll_src = ADAV80X_PLL_CLK_SRC_PLL_XIN(pll_id); | ||
662 | |||
663 | snd_soc_update_bits(codec, ADAV80X_PLL_CLK_SRC, | ||
664 | ADAV80X_PLL_CLK_SRC_PLL_MASK(pll_id), pll_src); | ||
665 | |||
666 | adav80x->pll_src = source; | ||
667 | |||
668 | snd_soc_dapm_sync(&codec->dapm); | ||
669 | } | ||
670 | |||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | static int adav80x_set_bias_level(struct snd_soc_codec *codec, | ||
675 | enum snd_soc_bias_level level) | ||
676 | { | ||
677 | unsigned int mask = ADAV80X_DAC_CTRL1_PD; | ||
678 | |||
679 | switch (level) { | ||
680 | case SND_SOC_BIAS_ON: | ||
681 | break; | ||
682 | case SND_SOC_BIAS_PREPARE: | ||
683 | break; | ||
684 | case SND_SOC_BIAS_STANDBY: | ||
685 | snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, 0x00); | ||
686 | break; | ||
687 | case SND_SOC_BIAS_OFF: | ||
688 | snd_soc_update_bits(codec, ADAV80X_DAC_CTRL1, mask, mask); | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | codec->dapm.bias_level = level; | ||
693 | return 0; | ||
694 | } | ||
695 | |||
696 | /* Enforce the same sample rate on all audio interfaces */ | ||
697 | static int adav80x_dai_startup(struct snd_pcm_substream *substream, | ||
698 | struct snd_soc_dai *dai) | ||
699 | { | ||
700 | struct snd_soc_codec *codec = dai->codec; | ||
701 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
702 | |||
703 | if (!codec->active || !adav80x->rate) | ||
704 | return 0; | ||
705 | |||
706 | return snd_pcm_hw_constraint_minmax(substream->runtime, | ||
707 | SNDRV_PCM_HW_PARAM_RATE, adav80x->rate, adav80x->rate); | ||
708 | } | ||
709 | |||
710 | static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, | ||
711 | struct snd_soc_dai *dai) | ||
712 | { | ||
713 | struct snd_soc_codec *codec = dai->codec; | ||
714 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
715 | |||
716 | if (!codec->active) | ||
717 | adav80x->rate = 0; | ||
718 | } | ||
719 | |||
720 | static const struct snd_soc_dai_ops adav80x_dai_ops = { | ||
721 | .set_fmt = adav80x_set_dai_fmt, | ||
722 | .hw_params = adav80x_hw_params, | ||
723 | .startup = adav80x_dai_startup, | ||
724 | .shutdown = adav80x_dai_shutdown, | ||
725 | }; | ||
726 | |||
727 | #define ADAV80X_PLAYBACK_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
728 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | \ | ||
729 | SNDRV_PCM_RATE_96000) | ||
730 | |||
731 | #define ADAV80X_CAPTURE_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000) | ||
732 | |||
733 | #define ADAV80X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ | ||
734 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
735 | |||
736 | static struct snd_soc_dai_driver adav80x_dais[] = { | ||
737 | { | ||
738 | .name = "adav80x-hifi", | ||
739 | .id = 0, | ||
740 | .playback = { | ||
741 | .stream_name = "HiFi Playback", | ||
742 | .channels_min = 2, | ||
743 | .channels_max = 2, | ||
744 | .rates = ADAV80X_PLAYBACK_RATES, | ||
745 | .formats = ADAV80X_FORMATS, | ||
746 | }, | ||
747 | .capture = { | ||
748 | .stream_name = "HiFi Capture", | ||
749 | .channels_min = 2, | ||
750 | .channels_max = 2, | ||
751 | .rates = ADAV80X_CAPTURE_RATES, | ||
752 | .formats = ADAV80X_FORMATS, | ||
753 | }, | ||
754 | .ops = &adav80x_dai_ops, | ||
755 | }, | ||
756 | { | ||
757 | .name = "adav80x-aux", | ||
758 | .id = 1, | ||
759 | .playback = { | ||
760 | .stream_name = "Aux Playback", | ||
761 | .channels_min = 2, | ||
762 | .channels_max = 2, | ||
763 | .rates = ADAV80X_PLAYBACK_RATES, | ||
764 | .formats = ADAV80X_FORMATS, | ||
765 | }, | ||
766 | .capture = { | ||
767 | .stream_name = "Aux Capture", | ||
768 | .channels_min = 2, | ||
769 | .channels_max = 2, | ||
770 | .rates = ADAV80X_CAPTURE_RATES, | ||
771 | .formats = ADAV80X_FORMATS, | ||
772 | }, | ||
773 | .ops = &adav80x_dai_ops, | ||
774 | }, | ||
775 | }; | ||
776 | |||
777 | static int adav80x_probe(struct snd_soc_codec *codec) | ||
778 | { | ||
779 | int ret; | ||
780 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
781 | |||
782 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, adav80x->control_type); | ||
783 | if (ret) { | ||
784 | dev_err(codec->dev, "failed to set cache I/O: %d\n", ret); | ||
785 | return ret; | ||
786 | } | ||
787 | |||
788 | /* Force PLLs on for SYSCLK output */ | ||
789 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | ||
790 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | ||
791 | |||
792 | /* Power down S/PDIF receiver, since it is currently not supported */ | ||
793 | snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x20); | ||
794 | /* Disable DAC zero flag */ | ||
795 | snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6); | ||
796 | |||
797 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
798 | } | ||
799 | |||
800 | static int adav80x_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
801 | { | ||
802 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
803 | } | ||
804 | |||
805 | static int adav80x_resume(struct snd_soc_codec *codec) | ||
806 | { | ||
807 | adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
808 | codec->cache_sync = 1; | ||
809 | snd_soc_cache_sync(codec); | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int adav80x_remove(struct snd_soc_codec *codec) | ||
815 | { | ||
816 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
817 | } | ||
818 | |||
819 | static struct snd_soc_codec_driver adav80x_codec_driver = { | ||
820 | .probe = adav80x_probe, | ||
821 | .remove = adav80x_remove, | ||
822 | .suspend = adav80x_suspend, | ||
823 | .resume = adav80x_resume, | ||
824 | .set_bias_level = adav80x_set_bias_level, | ||
825 | |||
826 | .set_pll = adav80x_set_pll, | ||
827 | .set_sysclk = adav80x_set_sysclk, | ||
828 | |||
829 | .reg_word_size = sizeof(u8), | ||
830 | .reg_cache_size = ARRAY_SIZE(adav80x_default_regs), | ||
831 | .reg_cache_default = adav80x_default_regs, | ||
832 | |||
833 | .controls = adav80x_controls, | ||
834 | .num_controls = ARRAY_SIZE(adav80x_controls), | ||
835 | .dapm_widgets = adav80x_dapm_widgets, | ||
836 | .num_dapm_widgets = ARRAY_SIZE(adav80x_dapm_widgets), | ||
837 | .dapm_routes = adav80x_dapm_routes, | ||
838 | .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), | ||
839 | }; | ||
840 | |||
841 | static int __devinit adav80x_bus_probe(struct device *dev, | ||
842 | enum snd_soc_control_type control_type) | ||
843 | { | ||
844 | struct adav80x *adav80x; | ||
845 | int ret; | ||
846 | |||
847 | adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); | ||
848 | if (!adav80x) | ||
849 | return -ENOMEM; | ||
850 | |||
851 | dev_set_drvdata(dev, adav80x); | ||
852 | adav80x->control_type = control_type; | ||
853 | |||
854 | ret = snd_soc_register_codec(dev, &adav80x_codec_driver, | ||
855 | adav80x_dais, ARRAY_SIZE(adav80x_dais)); | ||
856 | if (ret) | ||
857 | kfree(adav80x); | ||
858 | |||
859 | return ret; | ||
860 | } | ||
861 | |||
862 | static int __devexit adav80x_bus_remove(struct device *dev) | ||
863 | { | ||
864 | snd_soc_unregister_codec(dev); | ||
865 | kfree(dev_get_drvdata(dev)); | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | #if defined(CONFIG_SPI_MASTER) | ||
870 | static int __devinit adav80x_spi_probe(struct spi_device *spi) | ||
871 | { | ||
872 | return adav80x_bus_probe(&spi->dev, SND_SOC_SPI); | ||
873 | } | ||
874 | |||
875 | static int __devexit adav80x_spi_remove(struct spi_device *spi) | ||
876 | { | ||
877 | return adav80x_bus_remove(&spi->dev); | ||
878 | } | ||
879 | |||
880 | static struct spi_driver adav80x_spi_driver = { | ||
881 | .driver = { | ||
882 | .name = "adav801", | ||
883 | .owner = THIS_MODULE, | ||
884 | }, | ||
885 | .probe = adav80x_spi_probe, | ||
886 | .remove = __devexit_p(adav80x_spi_remove), | ||
887 | }; | ||
888 | #endif | ||
889 | |||
890 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
891 | static const struct i2c_device_id adav80x_id[] = { | ||
892 | { "adav803", 0 }, | ||
893 | { } | ||
894 | }; | ||
895 | MODULE_DEVICE_TABLE(i2c, adav80x_id); | ||
896 | |||
897 | static int __devinit adav80x_i2c_probe(struct i2c_client *client, | ||
898 | const struct i2c_device_id *id) | ||
899 | { | ||
900 | return adav80x_bus_probe(&client->dev, SND_SOC_I2C); | ||
901 | } | ||
902 | |||
903 | static int __devexit adav80x_i2c_remove(struct i2c_client *client) | ||
904 | { | ||
905 | return adav80x_bus_remove(&client->dev); | ||
906 | } | ||
907 | |||
908 | static struct i2c_driver adav80x_i2c_driver = { | ||
909 | .driver = { | ||
910 | .name = "adav803", | ||
911 | .owner = THIS_MODULE, | ||
912 | }, | ||
913 | .probe = adav80x_i2c_probe, | ||
914 | .remove = __devexit_p(adav80x_i2c_remove), | ||
915 | .id_table = adav80x_id, | ||
916 | }; | ||
917 | #endif | ||
918 | |||
919 | static int __init adav80x_init(void) | ||
920 | { | ||
921 | int ret = 0; | ||
922 | |||
923 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
924 | ret = i2c_add_driver(&adav80x_i2c_driver); | ||
925 | if (ret) | ||
926 | return ret; | ||
927 | #endif | ||
928 | |||
929 | #if defined(CONFIG_SPI_MASTER) | ||
930 | ret = spi_register_driver(&adav80x_spi_driver); | ||
931 | #endif | ||
932 | |||
933 | return ret; | ||
934 | } | ||
935 | module_init(adav80x_init); | ||
936 | |||
937 | static void __exit adav80x_exit(void) | ||
938 | { | ||
939 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
940 | i2c_del_driver(&adav80x_i2c_driver); | ||
941 | #endif | ||
942 | #if defined(CONFIG_SPI_MASTER) | ||
943 | spi_unregister_driver(&adav80x_spi_driver); | ||
944 | #endif | ||
945 | } | ||
946 | module_exit(adav80x_exit); | ||
947 | |||
948 | MODULE_DESCRIPTION("ASoC ADAV80x driver"); | ||
949 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
950 | MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); | ||
951 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h new file mode 100644 index 000000000000..adb0fc76d4e3 --- /dev/null +++ b/sound/soc/codecs/adav80x.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * header file for ADAV80X parts | ||
3 | * | ||
4 | * Copyright 2011 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #ifndef _ADAV80X_H | ||
10 | #define _ADAV80X_H | ||
11 | |||
12 | enum adav80x_pll_src { | ||
13 | ADAV80X_PLL_SRC_XIN, | ||
14 | ADAV80X_PLL_SRC_XTAL, | ||
15 | ADAV80X_PLL_SRC_MCLKI, | ||
16 | }; | ||
17 | |||
18 | enum adav80x_pll { | ||
19 | ADAV80X_PLL1 = 0, | ||
20 | ADAV80X_PLL2 = 1, | ||
21 | }; | ||
22 | |||
23 | enum adav80x_clk_src { | ||
24 | ADAV80X_CLK_XIN = 0, | ||
25 | ADAV80X_CLK_MCLKI = 1, | ||
26 | ADAV80X_CLK_PLL1 = 2, | ||
27 | ADAV80X_CLK_PLL2 = 3, | ||
28 | ADAV80X_CLK_XTAL = 6, | ||
29 | |||
30 | ADAV80X_CLK_SYSCLK1 = 6, | ||
31 | ADAV80X_CLK_SYSCLK2 = 7, | ||
32 | ADAV80X_CLK_SYSCLK3 = 8, | ||
33 | }; | ||
34 | |||
35 | #endif | ||
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index ed96f247c2da..7a64e58cddc4 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c | |||
@@ -457,7 +457,7 @@ static struct snd_soc_dai_ops ak4641_pcm_dai_ops = { | |||
457 | .set_sysclk = ak4641_set_dai_sysclk, | 457 | .set_sysclk = ak4641_set_dai_sysclk, |
458 | }; | 458 | }; |
459 | 459 | ||
460 | struct snd_soc_dai_driver ak4641_dai[] = { | 460 | static struct snd_soc_dai_driver ak4641_dai[] = { |
461 | { | 461 | { |
462 | .name = "ak4641-hifi", | 462 | .name = "ak4641-hifi", |
463 | .id = 1, | 463 | .id = 1, |
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 0206a17d7283..6cc8678f49f3 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -636,10 +636,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec) | |||
636 | #endif /* CONFIG_PM */ | 636 | #endif /* CONFIG_PM */ |
637 | 637 | ||
638 | /* | 638 | /* |
639 | * ASoC codec device structure | 639 | * ASoC codec driver structure |
640 | * | ||
641 | * Assign this variable to the codec_dev field of the machine driver's | ||
642 | * snd_soc_device structure. | ||
643 | */ | 640 | */ |
644 | static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { | 641 | static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { |
645 | .probe = cs4270_probe, | 642 | .probe = cs4270_probe, |
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 4173b67c94d1..ac65a2d36408 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
@@ -1397,8 +1397,6 @@ static int max98088_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1397 | if (freq == max98088->sysclk) | 1397 | if (freq == max98088->sysclk) |
1398 | return 0; | 1398 | return 0; |
1399 | 1399 | ||
1400 | max98088->sysclk = freq; /* remember current sysclk */ | ||
1401 | |||
1402 | /* Setup clocks for slave mode, and using the PLL | 1400 | /* Setup clocks for slave mode, and using the PLL |
1403 | * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) | 1401 | * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) |
1404 | * 0x02 (when master clk is 20MHz to 30MHz).. | 1402 | * 0x02 (when master clk is 20MHz to 30MHz).. |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index e1d282d477da..668434d44303 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -1517,8 +1517,6 @@ static int max98095_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1517 | if (freq == max98095->sysclk) | 1517 | if (freq == max98095->sysclk) |
1518 | return 0; | 1518 | return 0; |
1519 | 1519 | ||
1520 | max98095->sysclk = freq; /* remember current sysclk */ | ||
1521 | |||
1522 | /* Setup clocks for slave mode, and using the PLL | 1520 | /* Setup clocks for slave mode, and using the PLL |
1523 | * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) | 1521 | * PSCLK = 0x01 (when master clk is 10MHz to 20MHz) |
1524 | * 0x02 (when master clk is 20MHz to 40MHz).. | 1522 | * 0x02 (when master clk is 20MHz to 40MHz).. |
@@ -2261,11 +2259,11 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2261 | 2259 | ||
2262 | ret = snd_soc_read(codec, M98095_0FF_REV_ID); | 2260 | ret = snd_soc_read(codec, M98095_0FF_REV_ID); |
2263 | if (ret < 0) { | 2261 | if (ret < 0) { |
2264 | dev_err(codec->dev, "Failed to read device revision: %d\n", | 2262 | dev_err(codec->dev, "Failure reading hardware revision: %d\n", |
2265 | ret); | 2263 | ret); |
2266 | goto err_access; | 2264 | goto err_access; |
2267 | } | 2265 | } |
2268 | dev_info(codec->dev, "revision %c\n", ret + 'A'); | 2266 | dev_info(codec->dev, "Hardware revision: %c\n", ret - 0x40 + 'A'); |
2269 | 2267 | ||
2270 | snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); | 2268 | snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); |
2271 | 2269 | ||
@@ -2342,8 +2340,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c, | |||
2342 | max98095->control_data = i2c; | 2340 | max98095->control_data = i2c; |
2343 | max98095->pdata = i2c->dev.platform_data; | 2341 | max98095->pdata = i2c->dev.platform_data; |
2344 | 2342 | ||
2345 | ret = snd_soc_register_codec(&i2c->dev, | 2343 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095, |
2346 | &soc_codec_dev_max98095, &max98095_dai[0], 3); | 2344 | max98095_dai, ARRAY_SIZE(max98095_dai)); |
2347 | if (ret < 0) | 2345 | if (ret < 0) |
2348 | kfree(max98095); | 2346 | kfree(max98095); |
2349 | return ret; | 2347 | return ret; |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c new file mode 100644 index 000000000000..409d89d1f34c --- /dev/null +++ b/sound/soc/codecs/sta32x.c | |||
@@ -0,0 +1,917 @@ | |||
1 | /* | ||
2 | * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system | ||
3 | * | ||
4 | * Copyright: 2011 Raumfeld GmbH | ||
5 | * Author: Johannes Stezenbach <js@sig21.net> | ||
6 | * | ||
7 | * based on code from: | ||
8 | * Wolfson Microelectronics PLC. | ||
9 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
10 | * Freescale Semiconductor, Inc. | ||
11 | * Timur Tabi <timur@freescale.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ":%s:%d: " fmt, __func__, __LINE__ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/pm.h> | ||
26 | #include <linux/i2c.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/regulator/consumer.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include <sound/tlv.h> | ||
37 | |||
38 | #include "sta32x.h" | ||
39 | |||
40 | #define STA32X_RATES (SNDRV_PCM_RATE_32000 | \ | ||
41 | SNDRV_PCM_RATE_44100 | \ | ||
42 | SNDRV_PCM_RATE_48000 | \ | ||
43 | SNDRV_PCM_RATE_88200 | \ | ||
44 | SNDRV_PCM_RATE_96000 | \ | ||
45 | SNDRV_PCM_RATE_176400 | \ | ||
46 | SNDRV_PCM_RATE_192000) | ||
47 | |||
48 | #define STA32X_FORMATS \ | ||
49 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
50 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
51 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
52 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ | ||
53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ | ||
54 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE) | ||
55 | |||
56 | /* Power-up register defaults */ | ||
57 | static const u8 sta32x_regs[STA32X_REGISTER_COUNT] = { | ||
58 | 0x63, 0x80, 0xc2, 0x40, 0xc2, 0x5c, 0x10, 0xff, 0x60, 0x60, | ||
59 | 0x60, 0x80, 0x00, 0x00, 0x00, 0x40, 0x80, 0x77, 0x6a, 0x69, | ||
60 | 0x6a, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
61 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, | ||
62 | 0xc0, 0xf3, 0x33, 0x00, 0x0c, | ||
63 | }; | ||
64 | |||
65 | /* regulator power supply names */ | ||
66 | static const char *sta32x_supply_names[] = { | ||
67 | "Vdda", /* analog supply, 3.3VV */ | ||
68 | "Vdd3", /* digital supply, 3.3V */ | ||
69 | "Vcc" /* power amp spply, 10V - 36V */ | ||
70 | }; | ||
71 | |||
72 | /* codec private data */ | ||
73 | struct sta32x_priv { | ||
74 | struct regulator_bulk_data supplies[ARRAY_SIZE(sta32x_supply_names)]; | ||
75 | struct snd_soc_codec *codec; | ||
76 | |||
77 | unsigned int mclk; | ||
78 | unsigned int format; | ||
79 | }; | ||
80 | |||
81 | static const DECLARE_TLV_DB_SCALE(mvol_tlv, -12700, 50, 1); | ||
82 | static const DECLARE_TLV_DB_SCALE(chvol_tlv, -7950, 50, 1); | ||
83 | static const DECLARE_TLV_DB_SCALE(tone_tlv, -120, 200, 0); | ||
84 | |||
85 | static const char *sta32x_drc_ac[] = { | ||
86 | "Anti-Clipping", "Dynamic Range Compression" }; | ||
87 | static const char *sta32x_auto_eq_mode[] = { | ||
88 | "User", "Preset", "Loudness" }; | ||
89 | static const char *sta32x_auto_gc_mode[] = { | ||
90 | "User", "AC no clipping", "AC limited clipping (10%)", | ||
91 | "DRC nighttime listening mode" }; | ||
92 | static const char *sta32x_auto_xo_mode[] = { | ||
93 | "User", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz", "200Hz", | ||
94 | "220Hz", "240Hz", "260Hz", "280Hz", "300Hz", "320Hz", "340Hz", "360Hz" }; | ||
95 | static const char *sta32x_preset_eq_mode[] = { | ||
96 | "Flat", "Rock", "Soft Rock", "Jazz", "Classical", "Dance", "Pop", "Soft", | ||
97 | "Hard", "Party", "Vocal", "Hip-Hop", "Dialog", "Bass-boost #1", | ||
98 | "Bass-boost #2", "Bass-boost #3", "Loudness 1", "Loudness 2", | ||
99 | "Loudness 3", "Loudness 4", "Loudness 5", "Loudness 6", "Loudness 7", | ||
100 | "Loudness 8", "Loudness 9", "Loudness 10", "Loudness 11", "Loudness 12", | ||
101 | "Loudness 13", "Loudness 14", "Loudness 15", "Loudness 16" }; | ||
102 | static const char *sta32x_limiter_select[] = { | ||
103 | "Limiter Disabled", "Limiter #1", "Limiter #2" }; | ||
104 | static const char *sta32x_limiter_attack_rate[] = { | ||
105 | "3.1584", "2.7072", "2.2560", "1.8048", "1.3536", "0.9024", | ||
106 | "0.4512", "0.2256", "0.1504", "0.1123", "0.0902", "0.0752", | ||
107 | "0.0645", "0.0564", "0.0501", "0.0451" }; | ||
108 | static const char *sta32x_limiter_release_rate[] = { | ||
109 | "0.5116", "0.1370", "0.0744", "0.0499", "0.0360", "0.0299", | ||
110 | "0.0264", "0.0208", "0.0198", "0.0172", "0.0147", "0.0137", | ||
111 | "0.0134", "0.0117", "0.0110", "0.0104" }; | ||
112 | |||
113 | static const unsigned int sta32x_limiter_ac_attack_tlv[] = { | ||
114 | TLV_DB_RANGE_HEAD(2), | ||
115 | 0, 7, TLV_DB_SCALE_ITEM(-1200, 200, 0), | ||
116 | 8, 16, TLV_DB_SCALE_ITEM(300, 100, 0), | ||
117 | }; | ||
118 | |||
119 | static const unsigned int sta32x_limiter_ac_release_tlv[] = { | ||
120 | TLV_DB_RANGE_HEAD(5), | ||
121 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
122 | 1, 1, TLV_DB_SCALE_ITEM(-2900, 0, 0), | ||
123 | 2, 2, TLV_DB_SCALE_ITEM(-2000, 0, 0), | ||
124 | 3, 8, TLV_DB_SCALE_ITEM(-1400, 200, 0), | ||
125 | 8, 16, TLV_DB_SCALE_ITEM(-700, 100, 0), | ||
126 | }; | ||
127 | |||
128 | static const unsigned int sta32x_limiter_drc_attack_tlv[] = { | ||
129 | TLV_DB_RANGE_HEAD(3), | ||
130 | 0, 7, TLV_DB_SCALE_ITEM(-3100, 200, 0), | ||
131 | 8, 13, TLV_DB_SCALE_ITEM(-1600, 100, 0), | ||
132 | 14, 16, TLV_DB_SCALE_ITEM(-1000, 300, 0), | ||
133 | }; | ||
134 | |||
135 | static const unsigned int sta32x_limiter_drc_release_tlv[] = { | ||
136 | TLV_DB_RANGE_HEAD(5), | ||
137 | 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 0), | ||
138 | 1, 2, TLV_DB_SCALE_ITEM(-3800, 200, 0), | ||
139 | 3, 4, TLV_DB_SCALE_ITEM(-3300, 200, 0), | ||
140 | 5, 12, TLV_DB_SCALE_ITEM(-3000, 200, 0), | ||
141 | 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), | ||
142 | }; | ||
143 | |||
144 | static const struct soc_enum sta32x_drc_ac_enum = | ||
145 | SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, | ||
146 | 2, sta32x_drc_ac); | ||
147 | static const struct soc_enum sta32x_auto_eq_enum = | ||
148 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, | ||
149 | 3, sta32x_auto_eq_mode); | ||
150 | static const struct soc_enum sta32x_auto_gc_enum = | ||
151 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, | ||
152 | 4, sta32x_auto_gc_mode); | ||
153 | static const struct soc_enum sta32x_auto_xo_enum = | ||
154 | SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, | ||
155 | 16, sta32x_auto_xo_mode); | ||
156 | static const struct soc_enum sta32x_preset_eq_enum = | ||
157 | SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, | ||
158 | 32, sta32x_preset_eq_mode); | ||
159 | static const struct soc_enum sta32x_limiter_ch1_enum = | ||
160 | SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, | ||
161 | 3, sta32x_limiter_select); | ||
162 | static const struct soc_enum sta32x_limiter_ch2_enum = | ||
163 | SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, | ||
164 | 3, sta32x_limiter_select); | ||
165 | static const struct soc_enum sta32x_limiter_ch3_enum = | ||
166 | SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, | ||
167 | 3, sta32x_limiter_select); | ||
168 | static const struct soc_enum sta32x_limiter1_attack_rate_enum = | ||
169 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, | ||
170 | 16, sta32x_limiter_attack_rate); | ||
171 | static const struct soc_enum sta32x_limiter2_attack_rate_enum = | ||
172 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, | ||
173 | 16, sta32x_limiter_attack_rate); | ||
174 | static const struct soc_enum sta32x_limiter1_release_rate_enum = | ||
175 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, | ||
176 | 16, sta32x_limiter_release_rate); | ||
177 | static const struct soc_enum sta32x_limiter2_release_rate_enum = | ||
178 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, | ||
179 | 16, sta32x_limiter_release_rate); | ||
180 | |||
181 | /* byte array controls for setting biquad, mixer, scaling coefficients; | ||
182 | * for biquads all five coefficients need to be set in one go, | ||
183 | * mixer and pre/postscale coefs can be set individually; | ||
184 | * each coef is 24bit, the bytes are ordered in the same way | ||
185 | * as given in the STA32x data sheet (big endian; b1, b2, a1, a2, b0) | ||
186 | */ | ||
187 | |||
188 | static int sta32x_coefficient_info(struct snd_kcontrol *kcontrol, | ||
189 | struct snd_ctl_elem_info *uinfo) | ||
190 | { | ||
191 | int numcoef = kcontrol->private_value >> 16; | ||
192 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
193 | uinfo->count = 3 * numcoef; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int sta32x_coefficient_get(struct snd_kcontrol *kcontrol, | ||
198 | struct snd_ctl_elem_value *ucontrol) | ||
199 | { | ||
200 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
201 | int numcoef = kcontrol->private_value >> 16; | ||
202 | int index = kcontrol->private_value & 0xffff; | ||
203 | unsigned int cfud; | ||
204 | int i; | ||
205 | |||
206 | /* preserve reserved bits in STA32X_CFUD */ | ||
207 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
208 | /* chip documentation does not say if the bits are self clearing, | ||
209 | * so do it explicitly */ | ||
210 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
211 | |||
212 | snd_soc_write(codec, STA32X_CFADDR2, index); | ||
213 | if (numcoef == 1) | ||
214 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x04); | ||
215 | else if (numcoef == 5) | ||
216 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x08); | ||
217 | else | ||
218 | return -EINVAL; | ||
219 | for (i = 0; i < 3 * numcoef; i++) | ||
220 | ucontrol->value.bytes.data[i] = | ||
221 | snd_soc_read(codec, STA32X_B1CF1 + i); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int sta32x_coefficient_put(struct snd_kcontrol *kcontrol, | ||
227 | struct snd_ctl_elem_value *ucontrol) | ||
228 | { | ||
229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
230 | int numcoef = kcontrol->private_value >> 16; | ||
231 | int index = kcontrol->private_value & 0xffff; | ||
232 | unsigned int cfud; | ||
233 | int i; | ||
234 | |||
235 | /* preserve reserved bits in STA32X_CFUD */ | ||
236 | cfud = snd_soc_read(codec, STA32X_CFUD) & 0xf0; | ||
237 | /* chip documentation does not say if the bits are self clearing, | ||
238 | * so do it explicitly */ | ||
239 | snd_soc_write(codec, STA32X_CFUD, cfud); | ||
240 | |||
241 | snd_soc_write(codec, STA32X_CFADDR2, index); | ||
242 | for (i = 0; i < 3 * numcoef; i++) | ||
243 | snd_soc_write(codec, STA32X_B1CF1 + i, | ||
244 | ucontrol->value.bytes.data[i]); | ||
245 | if (numcoef == 1) | ||
246 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x01); | ||
247 | else if (numcoef == 5) | ||
248 | snd_soc_write(codec, STA32X_CFUD, cfud | 0x02); | ||
249 | else | ||
250 | return -EINVAL; | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | #define SINGLE_COEF(xname, index) \ | ||
256 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
257 | .info = sta32x_coefficient_info, \ | ||
258 | .get = sta32x_coefficient_get,\ | ||
259 | .put = sta32x_coefficient_put, \ | ||
260 | .private_value = index | (1 << 16) } | ||
261 | |||
262 | #define BIQUAD_COEFS(xname, index) \ | ||
263 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
264 | .info = sta32x_coefficient_info, \ | ||
265 | .get = sta32x_coefficient_get,\ | ||
266 | .put = sta32x_coefficient_put, \ | ||
267 | .private_value = index | (5 << 16) } | ||
268 | |||
269 | static const struct snd_kcontrol_new sta32x_snd_controls[] = { | ||
270 | SOC_SINGLE_TLV("Master Volume", STA32X_MVOL, 0, 0xff, 1, mvol_tlv), | ||
271 | SOC_SINGLE("Master Switch", STA32X_MMUTE, 0, 1, 1), | ||
272 | SOC_SINGLE("Ch1 Switch", STA32X_MMUTE, 1, 1, 1), | ||
273 | SOC_SINGLE("Ch2 Switch", STA32X_MMUTE, 2, 1, 1), | ||
274 | SOC_SINGLE("Ch3 Switch", STA32X_MMUTE, 3, 1, 1), | ||
275 | SOC_SINGLE_TLV("Ch1 Volume", STA32X_C1VOL, 0, 0xff, 1, chvol_tlv), | ||
276 | SOC_SINGLE_TLV("Ch2 Volume", STA32X_C2VOL, 0, 0xff, 1, chvol_tlv), | ||
277 | SOC_SINGLE_TLV("Ch3 Volume", STA32X_C3VOL, 0, 0xff, 1, chvol_tlv), | ||
278 | SOC_SINGLE("De-emphasis Filter Switch", STA32X_CONFD, STA32X_CONFD_DEMP_SHIFT, 1, 0), | ||
279 | SOC_ENUM("Compressor/Limiter Switch", sta32x_drc_ac_enum), | ||
280 | SOC_SINGLE("Miami Mode Switch", STA32X_CONFD, STA32X_CONFD_MME_SHIFT, 1, 0), | ||
281 | SOC_SINGLE("Zero Cross Switch", STA32X_CONFE, STA32X_CONFE_ZCE_SHIFT, 1, 0), | ||
282 | SOC_SINGLE("Soft Ramp Switch", STA32X_CONFE, STA32X_CONFE_SVE_SHIFT, 1, 0), | ||
283 | SOC_SINGLE("Auto-Mute Switch", STA32X_CONFF, STA32X_CONFF_IDE_SHIFT, 1, 0), | ||
284 | SOC_ENUM("Automode EQ", sta32x_auto_eq_enum), | ||
285 | SOC_ENUM("Automode GC", sta32x_auto_gc_enum), | ||
286 | SOC_ENUM("Automode XO", sta32x_auto_xo_enum), | ||
287 | SOC_ENUM("Preset EQ", sta32x_preset_eq_enum), | ||
288 | SOC_SINGLE("Ch1 Tone Control Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), | ||
289 | SOC_SINGLE("Ch2 Tone Control Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_TCB_SHIFT, 1, 0), | ||
290 | SOC_SINGLE("Ch1 EQ Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), | ||
291 | SOC_SINGLE("Ch2 EQ Bypass Switch", STA32X_C2CFG, STA32X_CxCFG_EQBP_SHIFT, 1, 0), | ||
292 | SOC_SINGLE("Ch1 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
293 | SOC_SINGLE("Ch2 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
294 | SOC_SINGLE("Ch3 Master Volume Bypass Switch", STA32X_C1CFG, STA32X_CxCFG_VBP_SHIFT, 1, 0), | ||
295 | SOC_ENUM("Ch1 Limiter Select", sta32x_limiter_ch1_enum), | ||
296 | SOC_ENUM("Ch2 Limiter Select", sta32x_limiter_ch2_enum), | ||
297 | SOC_ENUM("Ch3 Limiter Select", sta32x_limiter_ch3_enum), | ||
298 | SOC_SINGLE_TLV("Bass Tone Control", STA32X_TONE, STA32X_TONE_BTC_SHIFT, 15, 0, tone_tlv), | ||
299 | SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, tone_tlv), | ||
300 | SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), | ||
301 | SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), | ||
302 | SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | ||
303 | SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | ||
304 | |||
305 | /* depending on mode, the attack/release thresholds have | ||
306 | * two different enum definitions; provide both | ||
307 | */ | ||
308 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, | ||
309 | 16, 0, sta32x_limiter_ac_attack_tlv), | ||
310 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, | ||
311 | 16, 0, sta32x_limiter_ac_attack_tlv), | ||
312 | SOC_SINGLE_TLV("Limiter1 Release Threshold (AC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, | ||
313 | 16, 0, sta32x_limiter_ac_release_tlv), | ||
314 | SOC_SINGLE_TLV("Limiter2 Release Threshold (AC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | ||
315 | 16, 0, sta32x_limiter_ac_release_tlv), | ||
316 | SOC_SINGLE_TLV("Limiter1 Attack Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxA_SHIFT, | ||
317 | 16, 0, sta32x_limiter_drc_attack_tlv), | ||
318 | SOC_SINGLE_TLV("Limiter2 Attack Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxA_SHIFT, | ||
319 | 16, 0, sta32x_limiter_drc_attack_tlv), | ||
320 | SOC_SINGLE_TLV("Limiter1 Release Threshold (DRC Mode)", STA32X_L1ATRT, STA32X_LxR_SHIFT, | ||
321 | 16, 0, sta32x_limiter_drc_release_tlv), | ||
322 | SOC_SINGLE_TLV("Limiter2 Release Threshold (DRC Mode)", STA32X_L2ATRT, STA32X_LxR_SHIFT, | ||
323 | 16, 0, sta32x_limiter_drc_release_tlv), | ||
324 | |||
325 | BIQUAD_COEFS("Ch1 - Biquad 1", 0), | ||
326 | BIQUAD_COEFS("Ch1 - Biquad 2", 5), | ||
327 | BIQUAD_COEFS("Ch1 - Biquad 3", 10), | ||
328 | BIQUAD_COEFS("Ch1 - Biquad 4", 15), | ||
329 | BIQUAD_COEFS("Ch2 - Biquad 1", 20), | ||
330 | BIQUAD_COEFS("Ch2 - Biquad 2", 25), | ||
331 | BIQUAD_COEFS("Ch2 - Biquad 3", 30), | ||
332 | BIQUAD_COEFS("Ch2 - Biquad 4", 35), | ||
333 | BIQUAD_COEFS("High-pass", 40), | ||
334 | BIQUAD_COEFS("Low-pass", 45), | ||
335 | SINGLE_COEF("Ch1 - Prescale", 50), | ||
336 | SINGLE_COEF("Ch2 - Prescale", 51), | ||
337 | SINGLE_COEF("Ch1 - Postscale", 52), | ||
338 | SINGLE_COEF("Ch2 - Postscale", 53), | ||
339 | SINGLE_COEF("Ch3 - Postscale", 54), | ||
340 | SINGLE_COEF("Thermal warning - Postscale", 55), | ||
341 | SINGLE_COEF("Ch1 - Mix 1", 56), | ||
342 | SINGLE_COEF("Ch1 - Mix 2", 57), | ||
343 | SINGLE_COEF("Ch2 - Mix 1", 58), | ||
344 | SINGLE_COEF("Ch2 - Mix 2", 59), | ||
345 | SINGLE_COEF("Ch3 - Mix 1", 60), | ||
346 | SINGLE_COEF("Ch3 - Mix 2", 61), | ||
347 | }; | ||
348 | |||
349 | static const struct snd_soc_dapm_widget sta32x_dapm_widgets[] = { | ||
350 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), | ||
351 | SND_SOC_DAPM_OUTPUT("LEFT"), | ||
352 | SND_SOC_DAPM_OUTPUT("RIGHT"), | ||
353 | SND_SOC_DAPM_OUTPUT("SUB"), | ||
354 | }; | ||
355 | |||
356 | static const struct snd_soc_dapm_route sta32x_dapm_routes[] = { | ||
357 | { "LEFT", NULL, "DAC" }, | ||
358 | { "RIGHT", NULL, "DAC" }, | ||
359 | { "SUB", NULL, "DAC" }, | ||
360 | }; | ||
361 | |||
362 | /* MCLK interpolation ratio per fs */ | ||
363 | static struct { | ||
364 | int fs; | ||
365 | int ir; | ||
366 | } interpolation_ratios[] = { | ||
367 | { 32000, 0 }, | ||
368 | { 44100, 0 }, | ||
369 | { 48000, 0 }, | ||
370 | { 88200, 1 }, | ||
371 | { 96000, 1 }, | ||
372 | { 176400, 2 }, | ||
373 | { 192000, 2 }, | ||
374 | }; | ||
375 | |||
376 | /* MCLK to fs clock ratios */ | ||
377 | static struct { | ||
378 | int ratio; | ||
379 | int mcs; | ||
380 | } mclk_ratios[3][7] = { | ||
381 | { { 768, 0 }, { 512, 1 }, { 384, 2 }, { 256, 3 }, | ||
382 | { 128, 4 }, { 576, 5 }, { 0, 0 } }, | ||
383 | { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, | ||
384 | { { 384, 2 }, { 256, 3 }, { 192, 4 }, { 128, 5 }, {64, 0 }, { 0, 0 } }, | ||
385 | }; | ||
386 | |||
387 | |||
388 | /** | ||
389 | * sta32x_set_dai_sysclk - configure MCLK | ||
390 | * @codec_dai: the codec DAI | ||
391 | * @clk_id: the clock ID (ignored) | ||
392 | * @freq: the MCLK input frequency | ||
393 | * @dir: the clock direction (ignored) | ||
394 | * | ||
395 | * The value of MCLK is used to determine which sample rates are supported | ||
396 | * by the STA32X, based on the mclk_ratios table. | ||
397 | * | ||
398 | * This function must be called by the machine driver's 'startup' function, | ||
399 | * otherwise the list of supported sample rates will not be available in | ||
400 | * time for ALSA. | ||
401 | * | ||
402 | * For setups with variable MCLKs, pass 0 as 'freq' argument. This will cause | ||
403 | * theoretically possible sample rates to be enabled. Call it again with a | ||
404 | * proper value set one the external clock is set (most probably you would do | ||
405 | * that from a machine's driver 'hw_param' hook. | ||
406 | */ | ||
407 | static int sta32x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
408 | int clk_id, unsigned int freq, int dir) | ||
409 | { | ||
410 | struct snd_soc_codec *codec = codec_dai->codec; | ||
411 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
412 | int i, j, ir, fs; | ||
413 | unsigned int rates = 0; | ||
414 | unsigned int rate_min = -1; | ||
415 | unsigned int rate_max = 0; | ||
416 | |||
417 | pr_debug("mclk=%u\n", freq); | ||
418 | sta32x->mclk = freq; | ||
419 | |||
420 | if (sta32x->mclk) { | ||
421 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) { | ||
422 | ir = interpolation_ratios[i].ir; | ||
423 | fs = interpolation_ratios[i].fs; | ||
424 | for (j = 0; mclk_ratios[ir][j].ratio; j++) { | ||
425 | if (mclk_ratios[ir][j].ratio * fs == freq) { | ||
426 | rates |= snd_pcm_rate_to_rate_bit(fs); | ||
427 | if (fs < rate_min) | ||
428 | rate_min = fs; | ||
429 | if (fs > rate_max) | ||
430 | rate_max = fs; | ||
431 | } | ||
432 | } | ||
433 | } | ||
434 | /* FIXME: soc should support a rate list */ | ||
435 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
436 | |||
437 | if (!rates) { | ||
438 | dev_err(codec->dev, "could not find a valid sample rate\n"); | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | } else { | ||
442 | /* enable all possible rates */ | ||
443 | rates = STA32X_RATES; | ||
444 | rate_min = 32000; | ||
445 | rate_max = 192000; | ||
446 | } | ||
447 | |||
448 | codec_dai->driver->playback.rates = rates; | ||
449 | codec_dai->driver->playback.rate_min = rate_min; | ||
450 | codec_dai->driver->playback.rate_max = rate_max; | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * sta32x_set_dai_fmt - configure the codec for the selected audio format | ||
456 | * @codec_dai: the codec DAI | ||
457 | * @fmt: a SND_SOC_DAIFMT_x value indicating the data format | ||
458 | * | ||
459 | * This function takes a bitmask of SND_SOC_DAIFMT_x bits and programs the | ||
460 | * codec accordingly. | ||
461 | */ | ||
462 | static int sta32x_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
463 | unsigned int fmt) | ||
464 | { | ||
465 | struct snd_soc_codec *codec = codec_dai->codec; | ||
466 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
467 | u8 confb = snd_soc_read(codec, STA32X_CONFB); | ||
468 | |||
469 | pr_debug("\n"); | ||
470 | confb &= ~(STA32X_CONFB_C1IM | STA32X_CONFB_C2IM); | ||
471 | |||
472 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
473 | case SND_SOC_DAIFMT_CBS_CFS: | ||
474 | break; | ||
475 | default: | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | |||
479 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
480 | case SND_SOC_DAIFMT_I2S: | ||
481 | case SND_SOC_DAIFMT_RIGHT_J: | ||
482 | case SND_SOC_DAIFMT_LEFT_J: | ||
483 | sta32x->format = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
484 | break; | ||
485 | default: | ||
486 | return -EINVAL; | ||
487 | } | ||
488 | |||
489 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
490 | case SND_SOC_DAIFMT_NB_NF: | ||
491 | confb |= STA32X_CONFB_C2IM; | ||
492 | break; | ||
493 | case SND_SOC_DAIFMT_NB_IF: | ||
494 | confb |= STA32X_CONFB_C1IM; | ||
495 | break; | ||
496 | default: | ||
497 | return -EINVAL; | ||
498 | } | ||
499 | |||
500 | snd_soc_write(codec, STA32X_CONFB, confb); | ||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * sta32x_hw_params - program the STA32X with the given hardware parameters. | ||
506 | * @substream: the audio stream | ||
507 | * @params: the hardware parameters to set | ||
508 | * @dai: the SOC DAI (ignored) | ||
509 | * | ||
510 | * This function programs the hardware with the values provided. | ||
511 | * Specifically, the sample rate and the data format. | ||
512 | */ | ||
513 | static int sta32x_hw_params(struct snd_pcm_substream *substream, | ||
514 | struct snd_pcm_hw_params *params, | ||
515 | struct snd_soc_dai *dai) | ||
516 | { | ||
517 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
518 | struct snd_soc_codec *codec = rtd->codec; | ||
519 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
520 | unsigned int rate; | ||
521 | int i, mcs = -1, ir = -1; | ||
522 | u8 confa, confb; | ||
523 | |||
524 | rate = params_rate(params); | ||
525 | pr_debug("rate: %u\n", rate); | ||
526 | for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++) | ||
527 | if (interpolation_ratios[i].fs == rate) | ||
528 | ir = interpolation_ratios[i].ir; | ||
529 | if (ir < 0) | ||
530 | return -EINVAL; | ||
531 | for (i = 0; mclk_ratios[ir][i].ratio; i++) | ||
532 | if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) | ||
533 | mcs = mclk_ratios[ir][i].mcs; | ||
534 | if (mcs < 0) | ||
535 | return -EINVAL; | ||
536 | |||
537 | confa = snd_soc_read(codec, STA32X_CONFA); | ||
538 | confa &= ~(STA32X_CONFA_MCS_MASK | STA32X_CONFA_IR_MASK); | ||
539 | confa |= (ir << STA32X_CONFA_IR_SHIFT) | (mcs << STA32X_CONFA_MCS_SHIFT); | ||
540 | |||
541 | confb = snd_soc_read(codec, STA32X_CONFB); | ||
542 | confb &= ~(STA32X_CONFB_SAI_MASK | STA32X_CONFB_SAIFB); | ||
543 | switch (params_format(params)) { | ||
544 | case SNDRV_PCM_FORMAT_S24_LE: | ||
545 | case SNDRV_PCM_FORMAT_S24_BE: | ||
546 | case SNDRV_PCM_FORMAT_S24_3LE: | ||
547 | case SNDRV_PCM_FORMAT_S24_3BE: | ||
548 | pr_debug("24bit\n"); | ||
549 | /* fall through */ | ||
550 | case SNDRV_PCM_FORMAT_S32_LE: | ||
551 | case SNDRV_PCM_FORMAT_S32_BE: | ||
552 | pr_debug("24bit or 32bit\n"); | ||
553 | switch (sta32x->format) { | ||
554 | case SND_SOC_DAIFMT_I2S: | ||
555 | confb |= 0x0; | ||
556 | break; | ||
557 | case SND_SOC_DAIFMT_LEFT_J: | ||
558 | confb |= 0x1; | ||
559 | break; | ||
560 | case SND_SOC_DAIFMT_RIGHT_J: | ||
561 | confb |= 0x2; | ||
562 | break; | ||
563 | } | ||
564 | |||
565 | break; | ||
566 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
567 | case SNDRV_PCM_FORMAT_S20_3BE: | ||
568 | pr_debug("20bit\n"); | ||
569 | switch (sta32x->format) { | ||
570 | case SND_SOC_DAIFMT_I2S: | ||
571 | confb |= 0x4; | ||
572 | break; | ||
573 | case SND_SOC_DAIFMT_LEFT_J: | ||
574 | confb |= 0x5; | ||
575 | break; | ||
576 | case SND_SOC_DAIFMT_RIGHT_J: | ||
577 | confb |= 0x6; | ||
578 | break; | ||
579 | } | ||
580 | |||
581 | break; | ||
582 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
583 | case SNDRV_PCM_FORMAT_S18_3BE: | ||
584 | pr_debug("18bit\n"); | ||
585 | switch (sta32x->format) { | ||
586 | case SND_SOC_DAIFMT_I2S: | ||
587 | confb |= 0x8; | ||
588 | break; | ||
589 | case SND_SOC_DAIFMT_LEFT_J: | ||
590 | confb |= 0x9; | ||
591 | break; | ||
592 | case SND_SOC_DAIFMT_RIGHT_J: | ||
593 | confb |= 0xa; | ||
594 | break; | ||
595 | } | ||
596 | |||
597 | break; | ||
598 | case SNDRV_PCM_FORMAT_S16_LE: | ||
599 | case SNDRV_PCM_FORMAT_S16_BE: | ||
600 | pr_debug("16bit\n"); | ||
601 | switch (sta32x->format) { | ||
602 | case SND_SOC_DAIFMT_I2S: | ||
603 | confb |= 0x0; | ||
604 | break; | ||
605 | case SND_SOC_DAIFMT_LEFT_J: | ||
606 | confb |= 0xd; | ||
607 | break; | ||
608 | case SND_SOC_DAIFMT_RIGHT_J: | ||
609 | confb |= 0xe; | ||
610 | break; | ||
611 | } | ||
612 | |||
613 | break; | ||
614 | default: | ||
615 | return -EINVAL; | ||
616 | } | ||
617 | |||
618 | snd_soc_write(codec, STA32X_CONFA, confa); | ||
619 | snd_soc_write(codec, STA32X_CONFB, confb); | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | /** | ||
624 | * sta32x_set_bias_level - DAPM callback | ||
625 | * @codec: the codec device | ||
626 | * @level: DAPM power level | ||
627 | * | ||
628 | * This is called by ALSA to put the codec into low power mode | ||
629 | * or to wake it up. If the codec is powered off completely | ||
630 | * all registers must be restored after power on. | ||
631 | */ | ||
632 | static int sta32x_set_bias_level(struct snd_soc_codec *codec, | ||
633 | enum snd_soc_bias_level level) | ||
634 | { | ||
635 | int ret; | ||
636 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
637 | |||
638 | pr_debug("level = %d\n", level); | ||
639 | switch (level) { | ||
640 | case SND_SOC_BIAS_ON: | ||
641 | break; | ||
642 | |||
643 | case SND_SOC_BIAS_PREPARE: | ||
644 | /* Full power on */ | ||
645 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
646 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
647 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); | ||
648 | break; | ||
649 | |||
650 | case SND_SOC_BIAS_STANDBY: | ||
651 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
652 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | ||
653 | sta32x->supplies); | ||
654 | if (ret != 0) { | ||
655 | dev_err(codec->dev, | ||
656 | "Failed to enable supplies: %d\n", ret); | ||
657 | return ret; | ||
658 | } | ||
659 | |||
660 | snd_soc_cache_sync(codec); | ||
661 | } | ||
662 | |||
663 | /* Power up to mute */ | ||
664 | /* FIXME */ | ||
665 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
666 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
667 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD); | ||
668 | |||
669 | break; | ||
670 | |||
671 | case SND_SOC_BIAS_OFF: | ||
672 | /* The chip runs through the power down sequence for us. */ | ||
673 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
674 | STA32X_CONFF_PWDN | STA32X_CONFF_EAPD, | ||
675 | STA32X_CONFF_PWDN); | ||
676 | msleep(300); | ||
677 | |||
678 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), | ||
679 | sta32x->supplies); | ||
680 | break; | ||
681 | } | ||
682 | codec->dapm.bias_level = level; | ||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static struct snd_soc_dai_ops sta32x_dai_ops = { | ||
687 | .hw_params = sta32x_hw_params, | ||
688 | .set_sysclk = sta32x_set_dai_sysclk, | ||
689 | .set_fmt = sta32x_set_dai_fmt, | ||
690 | }; | ||
691 | |||
692 | static struct snd_soc_dai_driver sta32x_dai = { | ||
693 | .name = "STA32X", | ||
694 | .playback = { | ||
695 | .stream_name = "Playback", | ||
696 | .channels_min = 2, | ||
697 | .channels_max = 2, | ||
698 | .rates = STA32X_RATES, | ||
699 | .formats = STA32X_FORMATS, | ||
700 | }, | ||
701 | .ops = &sta32x_dai_ops, | ||
702 | }; | ||
703 | |||
704 | #ifdef CONFIG_PM | ||
705 | static int sta32x_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
706 | { | ||
707 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | static int sta32x_resume(struct snd_soc_codec *codec) | ||
712 | { | ||
713 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
714 | return 0; | ||
715 | } | ||
716 | #else | ||
717 | #define sta32x_suspend NULL | ||
718 | #define sta32x_resume NULL | ||
719 | #endif | ||
720 | |||
721 | static int sta32x_probe(struct snd_soc_codec *codec) | ||
722 | { | ||
723 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
724 | int i, ret = 0; | ||
725 | |||
726 | sta32x->codec = codec; | ||
727 | |||
728 | /* regulators */ | ||
729 | for (i = 0; i < ARRAY_SIZE(sta32x->supplies); i++) | ||
730 | sta32x->supplies[i].supply = sta32x_supply_names[i]; | ||
731 | |||
732 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sta32x->supplies), | ||
733 | sta32x->supplies); | ||
734 | if (ret != 0) { | ||
735 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
736 | goto err; | ||
737 | } | ||
738 | |||
739 | ret = regulator_bulk_enable(ARRAY_SIZE(sta32x->supplies), | ||
740 | sta32x->supplies); | ||
741 | if (ret != 0) { | ||
742 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
743 | goto err_get; | ||
744 | } | ||
745 | |||
746 | /* Tell ASoC what kind of I/O to use to read the registers. ASoC will | ||
747 | * then do the I2C transactions itself. | ||
748 | */ | ||
749 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
750 | if (ret < 0) { | ||
751 | dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); | ||
752 | return ret; | ||
753 | } | ||
754 | |||
755 | /* read reg reset values into cache */ | ||
756 | for (i = 0; i < STA32X_REGISTER_COUNT; i++) | ||
757 | snd_soc_cache_write(codec, i, sta32x_regs[i]); | ||
758 | |||
759 | /* preserve reset values of reserved register bits */ | ||
760 | snd_soc_cache_write(codec, STA32X_CONFC, | ||
761 | codec->hw_read(codec, STA32X_CONFC)); | ||
762 | snd_soc_cache_write(codec, STA32X_CONFE, | ||
763 | codec->hw_read(codec, STA32X_CONFE)); | ||
764 | snd_soc_cache_write(codec, STA32X_CONFF, | ||
765 | codec->hw_read(codec, STA32X_CONFF)); | ||
766 | snd_soc_cache_write(codec, STA32X_MMUTE, | ||
767 | codec->hw_read(codec, STA32X_MMUTE)); | ||
768 | snd_soc_cache_write(codec, STA32X_AUTO1, | ||
769 | codec->hw_read(codec, STA32X_AUTO1)); | ||
770 | snd_soc_cache_write(codec, STA32X_AUTO3, | ||
771 | codec->hw_read(codec, STA32X_AUTO3)); | ||
772 | snd_soc_cache_write(codec, STA32X_C3CFG, | ||
773 | codec->hw_read(codec, STA32X_C3CFG)); | ||
774 | |||
775 | /* FIXME enable thermal warning adjustment and recovery */ | ||
776 | snd_soc_update_bits(codec, STA32X_CONFA, | ||
777 | STA32X_CONFA_TWAB | STA32X_CONFA_TWRB, 0); | ||
778 | |||
779 | /* FIXME select 2.1 mode */ | ||
780 | snd_soc_update_bits(codec, STA32X_CONFF, | ||
781 | STA32X_CONFF_OCFG_MASK, | ||
782 | 1 << STA32X_CONFF_OCFG_SHIFT); | ||
783 | |||
784 | /* FIXME channel to output mapping */ | ||
785 | snd_soc_update_bits(codec, STA32X_C1CFG, | ||
786 | STA32X_CxCFG_OM_MASK, | ||
787 | 0 << STA32X_CxCFG_OM_SHIFT); | ||
788 | snd_soc_update_bits(codec, STA32X_C2CFG, | ||
789 | STA32X_CxCFG_OM_MASK, | ||
790 | 1 << STA32X_CxCFG_OM_SHIFT); | ||
791 | snd_soc_update_bits(codec, STA32X_C3CFG, | ||
792 | STA32X_CxCFG_OM_MASK, | ||
793 | 2 << STA32X_CxCFG_OM_SHIFT); | ||
794 | |||
795 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
796 | /* Bias level configuration will have done an extra enable */ | ||
797 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
798 | |||
799 | return 0; | ||
800 | |||
801 | err_get: | ||
802 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
803 | err: | ||
804 | return ret; | ||
805 | } | ||
806 | |||
807 | static int sta32x_remove(struct snd_soc_codec *codec) | ||
808 | { | ||
809 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | ||
810 | |||
811 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
812 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
813 | |||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | static int sta32x_reg_is_volatile(struct snd_soc_codec *codec, | ||
818 | unsigned int reg) | ||
819 | { | ||
820 | switch (reg) { | ||
821 | case STA32X_CONFA ... STA32X_L2ATRT: | ||
822 | case STA32X_MPCC1 ... STA32X_FDRC2: | ||
823 | return 0; | ||
824 | } | ||
825 | return 1; | ||
826 | } | ||
827 | |||
828 | static const struct snd_soc_codec_driver sta32x_codec = { | ||
829 | .probe = sta32x_probe, | ||
830 | .remove = sta32x_remove, | ||
831 | .suspend = sta32x_suspend, | ||
832 | .resume = sta32x_resume, | ||
833 | .reg_cache_size = STA32X_REGISTER_COUNT, | ||
834 | .reg_word_size = sizeof(u8), | ||
835 | .volatile_register = sta32x_reg_is_volatile, | ||
836 | .set_bias_level = sta32x_set_bias_level, | ||
837 | .controls = sta32x_snd_controls, | ||
838 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), | ||
839 | .dapm_widgets = sta32x_dapm_widgets, | ||
840 | .num_dapm_widgets = ARRAY_SIZE(sta32x_dapm_widgets), | ||
841 | .dapm_routes = sta32x_dapm_routes, | ||
842 | .num_dapm_routes = ARRAY_SIZE(sta32x_dapm_routes), | ||
843 | }; | ||
844 | |||
845 | static __devinit int sta32x_i2c_probe(struct i2c_client *i2c, | ||
846 | const struct i2c_device_id *id) | ||
847 | { | ||
848 | struct sta32x_priv *sta32x; | ||
849 | int ret; | ||
850 | |||
851 | sta32x = kzalloc(sizeof(struct sta32x_priv), GFP_KERNEL); | ||
852 | if (!sta32x) | ||
853 | return -ENOMEM; | ||
854 | |||
855 | i2c_set_clientdata(i2c, sta32x); | ||
856 | |||
857 | ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1); | ||
858 | if (ret != 0) { | ||
859 | dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret); | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | static __devexit int sta32x_i2c_remove(struct i2c_client *client) | ||
867 | { | ||
868 | struct sta32x_priv *sta32x = i2c_get_clientdata(client); | ||
869 | struct snd_soc_codec *codec = sta32x->codec; | ||
870 | |||
871 | if (codec) | ||
872 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
873 | |||
874 | regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | ||
875 | |||
876 | if (codec) { | ||
877 | snd_soc_unregister_codec(&client->dev); | ||
878 | snd_soc_codec_set_drvdata(codec, NULL); | ||
879 | } | ||
880 | |||
881 | kfree(sta32x); | ||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static const struct i2c_device_id sta32x_i2c_id[] = { | ||
886 | { "sta326", 0 }, | ||
887 | { "sta328", 0 }, | ||
888 | { "sta329", 0 }, | ||
889 | { } | ||
890 | }; | ||
891 | MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); | ||
892 | |||
893 | static struct i2c_driver sta32x_i2c_driver = { | ||
894 | .driver = { | ||
895 | .name = "sta32x", | ||
896 | .owner = THIS_MODULE, | ||
897 | }, | ||
898 | .probe = sta32x_i2c_probe, | ||
899 | .remove = __devexit_p(sta32x_i2c_remove), | ||
900 | .id_table = sta32x_i2c_id, | ||
901 | }; | ||
902 | |||
903 | static int __init sta32x_init(void) | ||
904 | { | ||
905 | return i2c_add_driver(&sta32x_i2c_driver); | ||
906 | } | ||
907 | module_init(sta32x_init); | ||
908 | |||
909 | static void __exit sta32x_exit(void) | ||
910 | { | ||
911 | i2c_del_driver(&sta32x_i2c_driver); | ||
912 | } | ||
913 | module_exit(sta32x_exit); | ||
914 | |||
915 | MODULE_DESCRIPTION("ASoC STA32X driver"); | ||
916 | MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>"); | ||
917 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sta32x.h b/sound/soc/codecs/sta32x.h new file mode 100644 index 000000000000..b97ee5a75667 --- /dev/null +++ b/sound/soc/codecs/sta32x.h | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Codec driver for ST STA32x 2.1-channel high-efficiency digital audio system | ||
3 | * | ||
4 | * Copyright: 2011 Raumfeld GmbH | ||
5 | * Author: Johannes Stezenbach <js@sig21.net> | ||
6 | * | ||
7 | * based on code from: | ||
8 | * Wolfson Microelectronics PLC. | ||
9 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #ifndef _ASOC_STA_32X_H | ||
17 | #define _ASOC_STA_32X_H | ||
18 | |||
19 | /* STA326 register addresses */ | ||
20 | |||
21 | #define STA32X_REGISTER_COUNT 0x2d | ||
22 | |||
23 | #define STA32X_CONFA 0x00 | ||
24 | #define STA32X_CONFB 0x01 | ||
25 | #define STA32X_CONFC 0x02 | ||
26 | #define STA32X_CONFD 0x03 | ||
27 | #define STA32X_CONFE 0x04 | ||
28 | #define STA32X_CONFF 0x05 | ||
29 | #define STA32X_MMUTE 0x06 | ||
30 | #define STA32X_MVOL 0x07 | ||
31 | #define STA32X_C1VOL 0x08 | ||
32 | #define STA32X_C2VOL 0x09 | ||
33 | #define STA32X_C3VOL 0x0a | ||
34 | #define STA32X_AUTO1 0x0b | ||
35 | #define STA32X_AUTO2 0x0c | ||
36 | #define STA32X_AUTO3 0x0d | ||
37 | #define STA32X_C1CFG 0x0e | ||
38 | #define STA32X_C2CFG 0x0f | ||
39 | #define STA32X_C3CFG 0x10 | ||
40 | #define STA32X_TONE 0x11 | ||
41 | #define STA32X_L1AR 0x12 | ||
42 | #define STA32X_L1ATRT 0x13 | ||
43 | #define STA32X_L2AR 0x14 | ||
44 | #define STA32X_L2ATRT 0x15 | ||
45 | #define STA32X_CFADDR2 0x16 | ||
46 | #define STA32X_B1CF1 0x17 | ||
47 | #define STA32X_B1CF2 0x18 | ||
48 | #define STA32X_B1CF3 0x19 | ||
49 | #define STA32X_B2CF1 0x1a | ||
50 | #define STA32X_B2CF2 0x1b | ||
51 | #define STA32X_B2CF3 0x1c | ||
52 | #define STA32X_A1CF1 0x1d | ||
53 | #define STA32X_A1CF2 0x1e | ||
54 | #define STA32X_A1CF3 0x1f | ||
55 | #define STA32X_A2CF1 0x20 | ||
56 | #define STA32X_A2CF2 0x21 | ||
57 | #define STA32X_A2CF3 0x22 | ||
58 | #define STA32X_B0CF1 0x23 | ||
59 | #define STA32X_B0CF2 0x24 | ||
60 | #define STA32X_B0CF3 0x25 | ||
61 | #define STA32X_CFUD 0x26 | ||
62 | #define STA32X_MPCC1 0x27 | ||
63 | #define STA32X_MPCC2 0x28 | ||
64 | /* Reserved 0x29 */ | ||
65 | /* Reserved 0x2a */ | ||
66 | #define STA32X_Reserved 0x2a | ||
67 | #define STA32X_FDRC1 0x2b | ||
68 | #define STA32X_FDRC2 0x2c | ||
69 | /* Reserved 0x2d */ | ||
70 | |||
71 | |||
72 | /* STA326 register field definitions */ | ||
73 | |||
74 | /* 0x00 CONFA */ | ||
75 | #define STA32X_CONFA_MCS_MASK 0x03 | ||
76 | #define STA32X_CONFA_MCS_SHIFT 0 | ||
77 | #define STA32X_CONFA_IR_MASK 0x18 | ||
78 | #define STA32X_CONFA_IR_SHIFT 3 | ||
79 | #define STA32X_CONFA_TWRB 0x20 | ||
80 | #define STA32X_CONFA_TWAB 0x40 | ||
81 | #define STA32X_CONFA_FDRB 0x80 | ||
82 | |||
83 | /* 0x01 CONFB */ | ||
84 | #define STA32X_CONFB_SAI_MASK 0x0f | ||
85 | #define STA32X_CONFB_SAI_SHIFT 0 | ||
86 | #define STA32X_CONFB_SAIFB 0x10 | ||
87 | #define STA32X_CONFB_DSCKE 0x20 | ||
88 | #define STA32X_CONFB_C1IM 0x40 | ||
89 | #define STA32X_CONFB_C2IM 0x80 | ||
90 | |||
91 | /* 0x02 CONFC */ | ||
92 | #define STA32X_CONFC_OM_MASK 0x03 | ||
93 | #define STA32X_CONFC_OM_SHIFT 0 | ||
94 | #define STA32X_CONFC_CSZ_MASK 0x7c | ||
95 | #define STA32X_CONFC_CSZ_SHIFT 2 | ||
96 | |||
97 | /* 0x03 CONFD */ | ||
98 | #define STA32X_CONFD_HPB 0x01 | ||
99 | #define STA32X_CONFD_HPB_SHIFT 0 | ||
100 | #define STA32X_CONFD_DEMP 0x02 | ||
101 | #define STA32X_CONFD_DEMP_SHIFT 1 | ||
102 | #define STA32X_CONFD_DSPB 0x04 | ||
103 | #define STA32X_CONFD_DSPB_SHIFT 2 | ||
104 | #define STA32X_CONFD_PSL 0x08 | ||
105 | #define STA32X_CONFD_PSL_SHIFT 3 | ||
106 | #define STA32X_CONFD_BQL 0x10 | ||
107 | #define STA32X_CONFD_BQL_SHIFT 4 | ||
108 | #define STA32X_CONFD_DRC 0x20 | ||
109 | #define STA32X_CONFD_DRC_SHIFT 5 | ||
110 | #define STA32X_CONFD_ZDE 0x40 | ||
111 | #define STA32X_CONFD_ZDE_SHIFT 6 | ||
112 | #define STA32X_CONFD_MME 0x80 | ||
113 | #define STA32X_CONFD_MME_SHIFT 7 | ||
114 | |||
115 | /* 0x04 CONFE */ | ||
116 | #define STA32X_CONFE_MPCV 0x01 | ||
117 | #define STA32X_CONFE_MPCV_SHIFT 0 | ||
118 | #define STA32X_CONFE_MPC 0x02 | ||
119 | #define STA32X_CONFE_MPC_SHIFT 1 | ||
120 | #define STA32X_CONFE_AME 0x08 | ||
121 | #define STA32X_CONFE_AME_SHIFT 3 | ||
122 | #define STA32X_CONFE_PWMS 0x10 | ||
123 | #define STA32X_CONFE_PWMS_SHIFT 4 | ||
124 | #define STA32X_CONFE_ZCE 0x40 | ||
125 | #define STA32X_CONFE_ZCE_SHIFT 6 | ||
126 | #define STA32X_CONFE_SVE 0x80 | ||
127 | #define STA32X_CONFE_SVE_SHIFT 7 | ||
128 | |||
129 | /* 0x05 CONFF */ | ||
130 | #define STA32X_CONFF_OCFG_MASK 0x03 | ||
131 | #define STA32X_CONFF_OCFG_SHIFT 0 | ||
132 | #define STA32X_CONFF_IDE 0x04 | ||
133 | #define STA32X_CONFF_IDE_SHIFT 3 | ||
134 | #define STA32X_CONFF_BCLE 0x08 | ||
135 | #define STA32X_CONFF_ECLE 0x20 | ||
136 | #define STA32X_CONFF_PWDN 0x40 | ||
137 | #define STA32X_CONFF_EAPD 0x80 | ||
138 | |||
139 | /* 0x06 MMUTE */ | ||
140 | #define STA32X_MMUTE_MMUTE 0x01 | ||
141 | |||
142 | /* 0x0b AUTO1 */ | ||
143 | #define STA32X_AUTO1_AMEQ_MASK 0x03 | ||
144 | #define STA32X_AUTO1_AMEQ_SHIFT 0 | ||
145 | #define STA32X_AUTO1_AMV_MASK 0xc0 | ||
146 | #define STA32X_AUTO1_AMV_SHIFT 2 | ||
147 | #define STA32X_AUTO1_AMGC_MASK 0x30 | ||
148 | #define STA32X_AUTO1_AMGC_SHIFT 4 | ||
149 | #define STA32X_AUTO1_AMPS 0x80 | ||
150 | |||
151 | /* 0x0c AUTO2 */ | ||
152 | #define STA32X_AUTO2_AMAME 0x01 | ||
153 | #define STA32X_AUTO2_AMAM_MASK 0x0e | ||
154 | #define STA32X_AUTO2_AMAM_SHIFT 1 | ||
155 | #define STA32X_AUTO2_XO_MASK 0xf0 | ||
156 | #define STA32X_AUTO2_XO_SHIFT 4 | ||
157 | |||
158 | /* 0x0d AUTO3 */ | ||
159 | #define STA32X_AUTO3_PEQ_MASK 0x1f | ||
160 | #define STA32X_AUTO3_PEQ_SHIFT 0 | ||
161 | |||
162 | /* 0x0e 0x0f 0x10 CxCFG */ | ||
163 | #define STA32X_CxCFG_TCB 0x01 /* only C1 and C2 */ | ||
164 | #define STA32X_CxCFG_TCB_SHIFT 0 | ||
165 | #define STA32X_CxCFG_EQBP 0x02 /* only C1 and C2 */ | ||
166 | #define STA32X_CxCFG_EQBP_SHIFT 1 | ||
167 | #define STA32X_CxCFG_VBP 0x03 | ||
168 | #define STA32X_CxCFG_VBP_SHIFT 2 | ||
169 | #define STA32X_CxCFG_BO 0x04 | ||
170 | #define STA32X_CxCFG_LS_MASK 0x30 | ||
171 | #define STA32X_CxCFG_LS_SHIFT 4 | ||
172 | #define STA32X_CxCFG_OM_MASK 0xc0 | ||
173 | #define STA32X_CxCFG_OM_SHIFT 6 | ||
174 | |||
175 | /* 0x11 TONE */ | ||
176 | #define STA32X_TONE_BTC_SHIFT 0 | ||
177 | #define STA32X_TONE_TTC_SHIFT 4 | ||
178 | |||
179 | /* 0x12 0x13 0x14 0x15 limiter attack/release */ | ||
180 | #define STA32X_LxA_SHIFT 0 | ||
181 | #define STA32X_LxR_SHIFT 4 | ||
182 | |||
183 | /* 0x26 CFUD */ | ||
184 | #define STA32X_CFUD_W1 0x01 | ||
185 | #define STA32X_CFUD_WA 0x02 | ||
186 | #define STA32X_CFUD_R1 0x04 | ||
187 | #define STA32X_CFUD_RA 0x08 | ||
188 | |||
189 | |||
190 | /* biquad filter coefficient table offsets */ | ||
191 | #define STA32X_C1_BQ_BASE 0 | ||
192 | #define STA32X_C2_BQ_BASE 20 | ||
193 | #define STA32X_CH_BQ_NUM 4 | ||
194 | #define STA32X_BQ_NUM_COEF 5 | ||
195 | #define STA32X_XO_HP_BQ_BASE 40 | ||
196 | #define STA32X_XO_LP_BQ_BASE 45 | ||
197 | #define STA32X_C1_PRESCALE 50 | ||
198 | #define STA32X_C2_PRESCALE 51 | ||
199 | #define STA32X_C1_POSTSCALE 52 | ||
200 | #define STA32X_C2_POSTSCALE 53 | ||
201 | #define STA32X_C3_POSTSCALE 54 | ||
202 | #define STA32X_TW_POSTSCALE 55 | ||
203 | #define STA32X_C1_MIX1 56 | ||
204 | #define STA32X_C1_MIX2 57 | ||
205 | #define STA32X_C2_MIX1 58 | ||
206 | #define STA32X_C2_MIX2 59 | ||
207 | #define STA32X_C3_MIX1 60 | ||
208 | #define STA32X_C3_MIX2 61 | ||
209 | |||
210 | #endif /* _ASOC_STA_32X_H */ | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 789453d44ec5..0963c4c7a83f 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -226,11 +226,13 @@ static const char *aic3x_adc_hpf[] = | |||
226 | #define RDAC_ENUM 1 | 226 | #define RDAC_ENUM 1 |
227 | #define LHPCOM_ENUM 2 | 227 | #define LHPCOM_ENUM 2 |
228 | #define RHPCOM_ENUM 3 | 228 | #define RHPCOM_ENUM 3 |
229 | #define LINE1L_ENUM 4 | 229 | #define LINE1L_2_L_ENUM 4 |
230 | #define LINE1R_ENUM 5 | 230 | #define LINE1L_2_R_ENUM 5 |
231 | #define LINE2L_ENUM 6 | 231 | #define LINE1R_2_L_ENUM 6 |
232 | #define LINE2R_ENUM 7 | 232 | #define LINE1R_2_R_ENUM 7 |
233 | #define ADC_HPF_ENUM 8 | 233 | #define LINE2L_ENUM 8 |
234 | #define LINE2R_ENUM 9 | ||
235 | #define ADC_HPF_ENUM 10 | ||
234 | 236 | ||
235 | static const struct soc_enum aic3x_enum[] = { | 237 | static const struct soc_enum aic3x_enum[] = { |
236 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | 238 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), |
@@ -238,6 +240,8 @@ static const struct soc_enum aic3x_enum[] = { | |||
238 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), | 240 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), |
239 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), | 241 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), |
240 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 242 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
243 | SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | ||
244 | SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | ||
241 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 245 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
242 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 246 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
243 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 247 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), |
@@ -490,12 +494,16 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { | |||
490 | }; | 494 | }; |
491 | 495 | ||
492 | /* Left Line1 Mux */ | 496 | /* Left Line1 Mux */ |
493 | static const struct snd_kcontrol_new aic3x_left_line1_mux_controls = | 497 | static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = |
494 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_ENUM]); | 498 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]); |
499 | static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = | ||
500 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]); | ||
495 | 501 | ||
496 | /* Right Line1 Mux */ | 502 | /* Right Line1 Mux */ |
497 | static const struct snd_kcontrol_new aic3x_right_line1_mux_controls = | 503 | static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = |
498 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_ENUM]); | 504 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]); |
505 | static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = | ||
506 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]); | ||
499 | 507 | ||
500 | /* Left Line2 Mux */ | 508 | /* Left Line2 Mux */ |
501 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = | 509 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = |
@@ -535,9 +543,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
535 | &aic3x_left_pga_mixer_controls[0], | 543 | &aic3x_left_pga_mixer_controls[0], |
536 | ARRAY_SIZE(aic3x_left_pga_mixer_controls)), | 544 | ARRAY_SIZE(aic3x_left_pga_mixer_controls)), |
537 | SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, | 545 | SND_SOC_DAPM_MUX("Left Line1L Mux", SND_SOC_NOPM, 0, 0, |
538 | &aic3x_left_line1_mux_controls), | 546 | &aic3x_left_line1l_mux_controls), |
539 | SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, | 547 | SND_SOC_DAPM_MUX("Left Line1R Mux", SND_SOC_NOPM, 0, 0, |
540 | &aic3x_left_line1_mux_controls), | 548 | &aic3x_left_line1r_mux_controls), |
541 | SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, | 549 | SND_SOC_DAPM_MUX("Left Line2L Mux", SND_SOC_NOPM, 0, 0, |
542 | &aic3x_left_line2_mux_controls), | 550 | &aic3x_left_line2_mux_controls), |
543 | 551 | ||
@@ -548,9 +556,9 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | |||
548 | &aic3x_right_pga_mixer_controls[0], | 556 | &aic3x_right_pga_mixer_controls[0], |
549 | ARRAY_SIZE(aic3x_right_pga_mixer_controls)), | 557 | ARRAY_SIZE(aic3x_right_pga_mixer_controls)), |
550 | SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, | 558 | SND_SOC_DAPM_MUX("Right Line1L Mux", SND_SOC_NOPM, 0, 0, |
551 | &aic3x_right_line1_mux_controls), | 559 | &aic3x_right_line1l_mux_controls), |
552 | SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, | 560 | SND_SOC_DAPM_MUX("Right Line1R Mux", SND_SOC_NOPM, 0, 0, |
553 | &aic3x_right_line1_mux_controls), | 561 | &aic3x_right_line1r_mux_controls), |
554 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, | 562 | SND_SOC_DAPM_MUX("Right Line2R Mux", SND_SOC_NOPM, 0, 0, |
555 | &aic3x_right_line2_mux_controls), | 563 | &aic3x_right_line2_mux_controls), |
556 | 564 | ||
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 4c336636d4f5..cd63bba623df 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -954,9 +954,9 @@ static DECLARE_TLV_DB_SCALE(mic_preamp_tlv, -600, 600, 0); | |||
954 | 954 | ||
955 | /* | 955 | /* |
956 | * MICGAIN volume control: | 956 | * MICGAIN volume control: |
957 | * from -6 to 30 dB in 6 dB steps | 957 | * from 6 to 30 dB in 6 dB steps |
958 | */ | 958 | */ |
959 | static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -600, 600, 0); | 959 | static DECLARE_TLV_DB_SCALE(mic_amp_tlv, 600, 600, 0); |
960 | 960 | ||
961 | /* | 961 | /* |
962 | * AFMGAIN volume control: | 962 | * AFMGAIN volume control: |
diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c new file mode 100644 index 000000000000..a2a09f85ea99 --- /dev/null +++ b/sound/soc/codecs/wm8782.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * sound/soc/codecs/wm8782.c | ||
3 | * simple, strap-pin configured 24bit 2ch ADC | ||
4 | * | ||
5 | * Copyright: 2011 Raumfeld GmbH | ||
6 | * Author: Johannes Stezenbach <js@sig21.net> | ||
7 | * | ||
8 | * based on ad73311.c | ||
9 | * Copyright: Analog Device Inc. | ||
10 | * Author: Cliff Cai <cliff.cai@analog.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/device.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/ac97_codec.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/soc.h> | ||
28 | |||
29 | static struct snd_soc_dai_driver wm8782_dai = { | ||
30 | .name = "wm8782", | ||
31 | .capture = { | ||
32 | .stream_name = "Capture", | ||
33 | .channels_min = 2, | ||
34 | .channels_max = 2, | ||
35 | /* For configurations with FSAMPEN=0 */ | ||
36 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
38 | SNDRV_PCM_FMTBIT_S20_3LE | | ||
39 | SNDRV_PCM_FMTBIT_S24_LE, | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | static struct snd_soc_codec_driver soc_codec_dev_wm8782; | ||
44 | |||
45 | static __devinit int wm8782_probe(struct platform_device *pdev) | ||
46 | { | ||
47 | return snd_soc_register_codec(&pdev->dev, | ||
48 | &soc_codec_dev_wm8782, &wm8782_dai, 1); | ||
49 | } | ||
50 | |||
51 | static int __devexit wm8782_remove(struct platform_device *pdev) | ||
52 | { | ||
53 | snd_soc_unregister_codec(&pdev->dev); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | static struct platform_driver wm8782_codec_driver = { | ||
58 | .driver = { | ||
59 | .name = "wm8782", | ||
60 | .owner = THIS_MODULE, | ||
61 | }, | ||
62 | .probe = wm8782_probe, | ||
63 | .remove = wm8782_remove, | ||
64 | }; | ||
65 | |||
66 | static int __init wm8782_init(void) | ||
67 | { | ||
68 | return platform_driver_register(&wm8782_codec_driver); | ||
69 | } | ||
70 | module_init(wm8782_init); | ||
71 | |||
72 | static void __exit wm8782_exit(void) | ||
73 | { | ||
74 | platform_driver_unregister(&wm8782_codec_driver); | ||
75 | } | ||
76 | module_exit(wm8782_exit); | ||
77 | |||
78 | MODULE_DESCRIPTION("ASoC WM8782 driver"); | ||
79 | MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>"); | ||
80 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 449ea09a193d..082040eda8a2 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -1167,6 +1167,7 @@ static int wm8900_resume(struct snd_soc_codec *codec) | |||
1167 | ret = wm8900_set_fll(codec, 0, fll_in, fll_out); | 1167 | ret = wm8900_set_fll(codec, 0, fll_in, fll_out); |
1168 | if (ret != 0) { | 1168 | if (ret != 0) { |
1169 | dev_err(codec->dev, "Failed to restart FLL\n"); | 1169 | dev_err(codec->dev, "Failed to restart FLL\n"); |
1170 | kfree(cache); | ||
1170 | return ret; | 1171 | return ret; |
1171 | } | 1172 | } |
1172 | } | 1173 | } |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 9b3bba4df5b3..b085575d4aa5 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -2560,6 +2560,7 @@ static __devexit int wm8904_i2c_remove(struct i2c_client *client) | |||
2560 | static const struct i2c_device_id wm8904_i2c_id[] = { | 2560 | static const struct i2c_device_id wm8904_i2c_id[] = { |
2561 | { "wm8904", WM8904 }, | 2561 | { "wm8904", WM8904 }, |
2562 | { "wm8912", WM8912 }, | 2562 | { "wm8912", WM8912 }, |
2563 | { "wm8918", WM8904 }, /* Actually a subset, updates to follow */ | ||
2563 | { } | 2564 | { } |
2564 | }; | 2565 | }; |
2565 | MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); | 2566 | MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); |
diff --git a/sound/soc/codecs/wm8915.c b/sound/soc/codecs/wm8915.c index e2ab4fac2819..423baa9be241 100644 --- a/sound/soc/codecs/wm8915.c +++ b/sound/soc/codecs/wm8915.c | |||
@@ -41,14 +41,12 @@ | |||
41 | #define HPOUT2L 4 | 41 | #define HPOUT2L 4 |
42 | #define HPOUT2R 8 | 42 | #define HPOUT2R 8 |
43 | 43 | ||
44 | #define WM8915_NUM_SUPPLIES 6 | 44 | #define WM8915_NUM_SUPPLIES 4 |
45 | static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { | 45 | static const char *wm8915_supply_names[WM8915_NUM_SUPPLIES] = { |
46 | "DCVDD", | ||
47 | "DBVDD", | 46 | "DBVDD", |
48 | "AVDD1", | 47 | "AVDD1", |
49 | "AVDD2", | 48 | "AVDD2", |
50 | "CPVDD", | 49 | "CPVDD", |
51 | "MICVDD", | ||
52 | }; | 50 | }; |
53 | 51 | ||
54 | struct wm8915_priv { | 52 | struct wm8915_priv { |
@@ -57,6 +55,7 @@ struct wm8915_priv { | |||
57 | int ldo1ena; | 55 | int ldo1ena; |
58 | 56 | ||
59 | int sysclk; | 57 | int sysclk; |
58 | int sysclk_src; | ||
60 | 59 | ||
61 | int fll_src; | 60 | int fll_src; |
62 | int fll_fref; | 61 | int fll_fref; |
@@ -76,6 +75,7 @@ struct wm8915_priv { | |||
76 | struct wm8915_pdata pdata; | 75 | struct wm8915_pdata pdata; |
77 | 76 | ||
78 | int rx_rate[WM8915_AIFS]; | 77 | int rx_rate[WM8915_AIFS]; |
78 | int bclk_rate[WM8915_AIFS]; | ||
79 | 79 | ||
80 | /* Platform dependant ReTune mobile configuration */ | 80 | /* Platform dependant ReTune mobile configuration */ |
81 | int num_retune_mobile_texts; | 81 | int num_retune_mobile_texts; |
@@ -113,8 +113,6 @@ WM8915_REGULATOR_EVENT(0) | |||
113 | WM8915_REGULATOR_EVENT(1) | 113 | WM8915_REGULATOR_EVENT(1) |
114 | WM8915_REGULATOR_EVENT(2) | 114 | WM8915_REGULATOR_EVENT(2) |
115 | WM8915_REGULATOR_EVENT(3) | 115 | WM8915_REGULATOR_EVENT(3) |
116 | WM8915_REGULATOR_EVENT(4) | ||
117 | WM8915_REGULATOR_EVENT(5) | ||
118 | 116 | ||
119 | static const u16 wm8915_reg[WM8915_MAX_REGISTER] = { | 117 | static const u16 wm8915_reg[WM8915_MAX_REGISTER] = { |
120 | [WM8915_SOFTWARE_RESET] = 0x8915, | 118 | [WM8915_SOFTWARE_RESET] = 0x8915, |
@@ -1565,6 +1563,50 @@ static int wm8915_reset(struct snd_soc_codec *codec) | |||
1565 | return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); | 1563 | return snd_soc_write(codec, WM8915_SOFTWARE_RESET, 0x8915); |
1566 | } | 1564 | } |
1567 | 1565 | ||
1566 | static const int bclk_divs[] = { | ||
1567 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 | ||
1568 | }; | ||
1569 | |||
1570 | static void wm8915_update_bclk(struct snd_soc_codec *codec) | ||
1571 | { | ||
1572 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | ||
1573 | int aif, best, cur_val, bclk_rate, bclk_reg, i; | ||
1574 | |||
1575 | /* Don't bother if we're in a low frequency idle mode that | ||
1576 | * can't support audio. | ||
1577 | */ | ||
1578 | if (wm8915->sysclk < 64000) | ||
1579 | return; | ||
1580 | |||
1581 | for (aif = 0; aif < WM8915_AIFS; aif++) { | ||
1582 | switch (aif) { | ||
1583 | case 0: | ||
1584 | bclk_reg = WM8915_AIF1_BCLK; | ||
1585 | break; | ||
1586 | case 1: | ||
1587 | bclk_reg = WM8915_AIF2_BCLK; | ||
1588 | break; | ||
1589 | } | ||
1590 | |||
1591 | bclk_rate = wm8915->bclk_rate[aif]; | ||
1592 | |||
1593 | /* Pick a divisor for BCLK as close as we can get to ideal */ | ||
1594 | best = 0; | ||
1595 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
1596 | cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; | ||
1597 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1598 | break; | ||
1599 | best = i; | ||
1600 | } | ||
1601 | bclk_rate = wm8915->sysclk / bclk_divs[best]; | ||
1602 | dev_dbg(codec->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", | ||
1603 | bclk_divs[best], bclk_rate); | ||
1604 | |||
1605 | snd_soc_update_bits(codec, bclk_reg, | ||
1606 | WM8915_AIF1_BCLK_DIV_MASK, best); | ||
1607 | } | ||
1608 | } | ||
1609 | |||
1568 | static int wm8915_set_bias_level(struct snd_soc_codec *codec, | 1610 | static int wm8915_set_bias_level(struct snd_soc_codec *codec, |
1569 | enum snd_soc_bias_level level) | 1611 | enum snd_soc_bias_level level) |
1570 | { | 1612 | { |
@@ -1717,10 +1759,6 @@ static int wm8915_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
1717 | return 0; | 1759 | return 0; |
1718 | } | 1760 | } |
1719 | 1761 | ||
1720 | static const int bclk_divs[] = { | ||
1721 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 | ||
1722 | }; | ||
1723 | |||
1724 | static const int dsp_divs[] = { | 1762 | static const int dsp_divs[] = { |
1725 | 48000, 32000, 16000, 8000 | 1763 | 48000, 32000, 16000, 8000 |
1726 | }; | 1764 | }; |
@@ -1731,17 +1769,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1731 | { | 1769 | { |
1732 | struct snd_soc_codec *codec = dai->codec; | 1770 | struct snd_soc_codec *codec = dai->codec; |
1733 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 1771 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
1734 | int bits, i, bclk_rate, best, cur_val; | 1772 | int bits, i, bclk_rate; |
1735 | int aifdata = 0; | 1773 | int aifdata = 0; |
1736 | int bclk = 0; | ||
1737 | int lrclk = 0; | 1774 | int lrclk = 0; |
1738 | int dsp = 0; | 1775 | int dsp = 0; |
1739 | int aifdata_reg, bclk_reg, lrclk_reg, dsp_shift; | 1776 | int aifdata_reg, lrclk_reg, dsp_shift; |
1740 | |||
1741 | if (!wm8915->sysclk) { | ||
1742 | dev_err(codec->dev, "SYSCLK not configured\n"); | ||
1743 | return -EINVAL; | ||
1744 | } | ||
1745 | 1777 | ||
1746 | switch (dai->id) { | 1778 | switch (dai->id) { |
1747 | case 0: | 1779 | case 0: |
@@ -1753,7 +1785,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1753 | aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; | 1785 | aifdata_reg = WM8915_AIF1TX_DATA_CONFIGURATION_1; |
1754 | lrclk_reg = WM8915_AIF1_TX_LRCLK_1; | 1786 | lrclk_reg = WM8915_AIF1_TX_LRCLK_1; |
1755 | } | 1787 | } |
1756 | bclk_reg = WM8915_AIF1_BCLK; | ||
1757 | dsp_shift = 0; | 1788 | dsp_shift = 0; |
1758 | break; | 1789 | break; |
1759 | case 1: | 1790 | case 1: |
@@ -1765,7 +1796,6 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1765 | aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; | 1796 | aifdata_reg = WM8915_AIF2TX_DATA_CONFIGURATION_1; |
1766 | lrclk_reg = WM8915_AIF2_TX_LRCLK_1; | 1797 | lrclk_reg = WM8915_AIF2_TX_LRCLK_1; |
1767 | } | 1798 | } |
1768 | bclk_reg = WM8915_AIF2_BCLK; | ||
1769 | dsp_shift = WM8915_DSP2_DIV_SHIFT; | 1799 | dsp_shift = WM8915_DSP2_DIV_SHIFT; |
1770 | break; | 1800 | break; |
1771 | default: | 1801 | default: |
@@ -1779,6 +1809,9 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1779 | return bclk_rate; | 1809 | return bclk_rate; |
1780 | } | 1810 | } |
1781 | 1811 | ||
1812 | wm8915->bclk_rate[dai->id] = bclk_rate; | ||
1813 | wm8915->rx_rate[dai->id] = params_rate(params); | ||
1814 | |||
1782 | /* Needs looking at for TDM */ | 1815 | /* Needs looking at for TDM */ |
1783 | bits = snd_pcm_format_width(params_format(params)); | 1816 | bits = snd_pcm_format_width(params_format(params)); |
1784 | if (bits < 0) | 1817 | if (bits < 0) |
@@ -1796,18 +1829,7 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1796 | } | 1829 | } |
1797 | dsp |= i << dsp_shift; | 1830 | dsp |= i << dsp_shift; |
1798 | 1831 | ||
1799 | /* Pick a divisor for BCLK as close as we can get to ideal */ | 1832 | wm8915_update_bclk(codec); |
1800 | best = 0; | ||
1801 | for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) { | ||
1802 | cur_val = (wm8915->sysclk / bclk_divs[i]) - bclk_rate; | ||
1803 | if (cur_val < 0) /* BCLK table is sorted */ | ||
1804 | break; | ||
1805 | best = i; | ||
1806 | } | ||
1807 | bclk_rate = wm8915->sysclk / bclk_divs[best]; | ||
1808 | dev_dbg(dai->dev, "Using BCLK_DIV %d for actual BCLK %dHz\n", | ||
1809 | bclk_divs[best], bclk_rate); | ||
1810 | bclk |= best; | ||
1811 | 1833 | ||
1812 | lrclk = bclk_rate / params_rate(params); | 1834 | lrclk = bclk_rate / params_rate(params); |
1813 | dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", | 1835 | dev_dbg(dai->dev, "Using LRCLK rate %d for actual LRCLK %dHz\n", |
@@ -1817,14 +1839,11 @@ static int wm8915_hw_params(struct snd_pcm_substream *substream, | |||
1817 | WM8915_AIF1TX_WL_MASK | | 1839 | WM8915_AIF1TX_WL_MASK | |
1818 | WM8915_AIF1TX_SLOT_LEN_MASK, | 1840 | WM8915_AIF1TX_SLOT_LEN_MASK, |
1819 | aifdata); | 1841 | aifdata); |
1820 | snd_soc_update_bits(codec, bclk_reg, WM8915_AIF1_BCLK_DIV_MASK, bclk); | ||
1821 | snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, | 1842 | snd_soc_update_bits(codec, lrclk_reg, WM8915_AIF1RX_RATE_MASK, |
1822 | lrclk); | 1843 | lrclk); |
1823 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, | 1844 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_2, |
1824 | WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); | 1845 | WM8915_DSP1_DIV_SHIFT << dsp_shift, dsp); |
1825 | 1846 | ||
1826 | wm8915->rx_rate[dai->id] = params_rate(params); | ||
1827 | |||
1828 | return 0; | 1847 | return 0; |
1829 | } | 1848 | } |
1830 | 1849 | ||
@@ -1838,6 +1857,9 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, | |||
1838 | int src; | 1857 | int src; |
1839 | int old; | 1858 | int old; |
1840 | 1859 | ||
1860 | if (freq == wm8915->sysclk && clk_id == wm8915->sysclk_src) | ||
1861 | return 0; | ||
1862 | |||
1841 | /* Disable SYSCLK while we reconfigure */ | 1863 | /* Disable SYSCLK while we reconfigure */ |
1842 | old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA; | 1864 | old = snd_soc_read(codec, WM8915_AIF_CLOCKING_1) & WM8915_SYSCLK_ENA; |
1843 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, | 1865 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, |
@@ -1882,6 +1904,8 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, | |||
1882 | return -EINVAL; | 1904 | return -EINVAL; |
1883 | } | 1905 | } |
1884 | 1906 | ||
1907 | wm8915_update_bclk(codec); | ||
1908 | |||
1885 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, | 1909 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, |
1886 | WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, | 1910 | WM8915_SYSCLK_SRC_MASK | WM8915_SYSCLK_DIV_MASK, |
1887 | src << WM8915_SYSCLK_SRC_SHIFT | ratediv); | 1911 | src << WM8915_SYSCLK_SRC_SHIFT | ratediv); |
@@ -1889,6 +1913,8 @@ static int wm8915_set_sysclk(struct snd_soc_dai *dai, | |||
1889 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, | 1913 | snd_soc_update_bits(codec, WM8915_AIF_CLOCKING_1, |
1890 | WM8915_SYSCLK_ENA, old); | 1914 | WM8915_SYSCLK_ENA, old); |
1891 | 1915 | ||
1916 | wm8915->sysclk_src = clk_id; | ||
1917 | |||
1892 | return 0; | 1918 | return 0; |
1893 | } | 1919 | } |
1894 | 1920 | ||
@@ -2007,6 +2033,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
2007 | unsigned int Fref, unsigned int Fout) | 2033 | unsigned int Fref, unsigned int Fout) |
2008 | { | 2034 | { |
2009 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 2035 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
2036 | struct i2c_client *i2c = to_i2c_client(codec->dev); | ||
2010 | struct _fll_div fll_div; | 2037 | struct _fll_div fll_div; |
2011 | unsigned long timeout; | 2038 | unsigned long timeout; |
2012 | int ret, reg; | 2039 | int ret, reg; |
@@ -2093,7 +2120,18 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
2093 | else | 2120 | else |
2094 | timeout = msecs_to_jiffies(2); | 2121 | timeout = msecs_to_jiffies(2); |
2095 | 2122 | ||
2096 | wait_for_completion_timeout(&wm8915->fll_lock, timeout); | 2123 | /* Allow substantially longer if we've actually got the IRQ */ |
2124 | if (i2c->irq) | ||
2125 | timeout *= 1000; | ||
2126 | |||
2127 | ret = wait_for_completion_timeout(&wm8915->fll_lock, timeout); | ||
2128 | |||
2129 | if (ret == 0 && i2c->irq) { | ||
2130 | dev_err(codec->dev, "Timed out waiting for FLL\n"); | ||
2131 | ret = -ETIMEDOUT; | ||
2132 | } else { | ||
2133 | ret = 0; | ||
2134 | } | ||
2097 | 2135 | ||
2098 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); | 2136 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); |
2099 | 2137 | ||
@@ -2101,7 +2139,7 @@ static int wm8915_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
2101 | wm8915->fll_fout = Fout; | 2139 | wm8915->fll_fout = Fout; |
2102 | wm8915->fll_src = source; | 2140 | wm8915->fll_src = source; |
2103 | 2141 | ||
2104 | return 0; | 2142 | return ret; |
2105 | } | 2143 | } |
2106 | 2144 | ||
2107 | #ifdef CONFIG_GPIOLIB | 2145 | #ifdef CONFIG_GPIOLIB |
@@ -2293,6 +2331,12 @@ static void wm8915_micd(struct snd_soc_codec *codec) | |||
2293 | SND_JACK_HEADSET | SND_JACK_BTN_0); | 2331 | SND_JACK_HEADSET | SND_JACK_BTN_0); |
2294 | wm8915->jack_mic = true; | 2332 | wm8915->jack_mic = true; |
2295 | wm8915->detecting = false; | 2333 | wm8915->detecting = false; |
2334 | |||
2335 | /* Increase poll rate to give better responsiveness | ||
2336 | * for buttons */ | ||
2337 | snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, | ||
2338 | WM8915_MICD_RATE_MASK, | ||
2339 | 5 << WM8915_MICD_RATE_SHIFT); | ||
2296 | } | 2340 | } |
2297 | 2341 | ||
2298 | /* If we detected a lower impedence during initial startup | 2342 | /* If we detected a lower impedence during initial startup |
@@ -2333,15 +2377,17 @@ static void wm8915_micd(struct snd_soc_codec *codec) | |||
2333 | SND_JACK_HEADPHONE, | 2377 | SND_JACK_HEADPHONE, |
2334 | SND_JACK_HEADSET | | 2378 | SND_JACK_HEADSET | |
2335 | SND_JACK_BTN_0); | 2379 | SND_JACK_BTN_0); |
2380 | |||
2381 | /* Increase the detection rate a bit for | ||
2382 | * responsiveness. | ||
2383 | */ | ||
2384 | snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, | ||
2385 | WM8915_MICD_RATE_MASK, | ||
2386 | 7 << WM8915_MICD_RATE_SHIFT); | ||
2387 | |||
2336 | wm8915->detecting = false; | 2388 | wm8915->detecting = false; |
2337 | } | 2389 | } |
2338 | } | 2390 | } |
2339 | |||
2340 | /* Increase poll rate to give better responsiveness for buttons */ | ||
2341 | if (!wm8915->detecting) | ||
2342 | snd_soc_update_bits(codec, WM8915_MIC_DETECT_1, | ||
2343 | WM8915_MICD_RATE_MASK, | ||
2344 | 5 << WM8915_MICD_RATE_SHIFT); | ||
2345 | } | 2391 | } |
2346 | 2392 | ||
2347 | static irqreturn_t wm8915_irq(int irq, void *data) | 2393 | static irqreturn_t wm8915_irq(int irq, void *data) |
@@ -2383,6 +2429,20 @@ static irqreturn_t wm8915_irq(int irq, void *data) | |||
2383 | } | 2429 | } |
2384 | } | 2430 | } |
2385 | 2431 | ||
2432 | static irqreturn_t wm8915_edge_irq(int irq, void *data) | ||
2433 | { | ||
2434 | irqreturn_t ret = IRQ_NONE; | ||
2435 | irqreturn_t val; | ||
2436 | |||
2437 | do { | ||
2438 | val = wm8915_irq(irq, data); | ||
2439 | if (val != IRQ_NONE) | ||
2440 | ret = val; | ||
2441 | } while (val != IRQ_NONE); | ||
2442 | |||
2443 | return ret; | ||
2444 | } | ||
2445 | |||
2386 | static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) | 2446 | static void wm8915_retune_mobile_pdata(struct snd_soc_codec *codec) |
2387 | { | 2447 | { |
2388 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); | 2448 | struct wm8915_priv *wm8915 = snd_soc_codec_get_drvdata(codec); |
@@ -2482,8 +2542,6 @@ static int wm8915_probe(struct snd_soc_codec *codec) | |||
2482 | wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1; | 2542 | wm8915->disable_nb[1].notifier_call = wm8915_regulator_event_1; |
2483 | wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2; | 2543 | wm8915->disable_nb[2].notifier_call = wm8915_regulator_event_2; |
2484 | wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3; | 2544 | wm8915->disable_nb[3].notifier_call = wm8915_regulator_event_3; |
2485 | wm8915->disable_nb[4].notifier_call = wm8915_regulator_event_4; | ||
2486 | wm8915->disable_nb[5].notifier_call = wm8915_regulator_event_5; | ||
2487 | 2545 | ||
2488 | /* This should really be moved into the regulator core */ | 2546 | /* This should really be moved into the regulator core */ |
2489 | for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) { | 2547 | for (i = 0; i < ARRAY_SIZE(wm8915->supplies); i++) { |
@@ -2709,8 +2767,14 @@ static int wm8915_probe(struct snd_soc_codec *codec) | |||
2709 | 2767 | ||
2710 | irq_flags |= IRQF_ONESHOT; | 2768 | irq_flags |= IRQF_ONESHOT; |
2711 | 2769 | ||
2712 | ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, | 2770 | if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) |
2713 | irq_flags, "wm8915", codec); | 2771 | ret = request_threaded_irq(i2c->irq, NULL, |
2772 | wm8915_edge_irq, | ||
2773 | irq_flags, "wm8915", codec); | ||
2774 | else | ||
2775 | ret = request_threaded_irq(i2c->irq, NULL, wm8915_irq, | ||
2776 | irq_flags, "wm8915", codec); | ||
2777 | |||
2714 | if (ret == 0) { | 2778 | if (ret == 0) { |
2715 | /* Unmask the interrupt */ | 2779 | /* Unmask the interrupt */ |
2716 | snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, | 2780 | snd_soc_update_bits(codec, WM8915_INTERRUPT_CONTROL, |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 25580e3ee7c4..056daa0010f9 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -297,8 +297,6 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec) | |||
297 | if (ret) | 297 | if (ret) |
298 | goto error_ret; | 298 | goto error_ret; |
299 | ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 299 | ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
300 | if (ret) | ||
301 | goto error_ret; | ||
302 | 300 | ||
303 | error_ret: | 301 | error_ret: |
304 | return ret; | 302 | return ret; |
@@ -683,8 +681,6 @@ static int wm8940_resume(struct snd_soc_codec *codec) | |||
683 | } | 681 | } |
684 | } | 682 | } |
685 | ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 683 | ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
686 | if (ret) | ||
687 | goto error_ret; | ||
688 | 684 | ||
689 | error_ret: | 685 | error_ret: |
690 | return ret; | 686 | return ret; |
@@ -730,9 +726,6 @@ static int wm8940_probe(struct snd_soc_codec *codec) | |||
730 | if (ret) | 726 | if (ret) |
731 | return ret; | 727 | return ret; |
732 | ret = wm8940_add_widgets(codec); | 728 | ret = wm8940_add_widgets(codec); |
733 | if (ret) | ||
734 | return ret; | ||
735 | |||
736 | return ret; | 729 | return ret; |
737 | } | 730 | } |
738 | 731 | ||
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 5e05eed96c38..8499c563a9b5 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -78,6 +78,8 @@ struct wm8962_priv { | |||
78 | #ifdef CONFIG_GPIOLIB | 78 | #ifdef CONFIG_GPIOLIB |
79 | struct gpio_chip gpio_chip; | 79 | struct gpio_chip gpio_chip; |
80 | #endif | 80 | #endif |
81 | |||
82 | int irq; | ||
81 | }; | 83 | }; |
82 | 84 | ||
83 | /* We can't use the same notifier block for more than one supply and | 85 | /* We can't use the same notifier block for more than one supply and |
@@ -1982,6 +1984,7 @@ static const unsigned int classd_tlv[] = { | |||
1982 | 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), | 1984 | 0, 6, TLV_DB_SCALE_ITEM(0, 150, 0), |
1983 | 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), | 1985 | 7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0), |
1984 | }; | 1986 | }; |
1987 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
1985 | 1988 | ||
1986 | /* The VU bits for the headphones are in a different register to the mute | 1989 | /* The VU bits for the headphones are in a different register to the mute |
1987 | * bits and only take effect on the PGA if it is actually powered. | 1990 | * bits and only take effect on the PGA if it is actually powered. |
@@ -2119,6 +2122,18 @@ SOC_SINGLE_TLV("HPMIXR MIXINR Volume", WM8962_HEADPHONE_MIXER_4, | |||
2119 | 2122 | ||
2120 | SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0, | 2123 | SOC_SINGLE_TLV("Speaker Boost Volume", WM8962_CLASS_D_CONTROL_2, 0, 7, 0, |
2121 | classd_tlv), | 2124 | classd_tlv), |
2125 | |||
2126 | SOC_SINGLE("EQ Switch", WM8962_EQ1, WM8962_EQ_ENA_SHIFT, 1, 0), | ||
2127 | SOC_DOUBLE_R_TLV("EQ1 Volume", WM8962_EQ2, WM8962_EQ22, | ||
2128 | WM8962_EQL_B1_GAIN_SHIFT, 31, 0, eq_tlv), | ||
2129 | SOC_DOUBLE_R_TLV("EQ2 Volume", WM8962_EQ2, WM8962_EQ22, | ||
2130 | WM8962_EQL_B2_GAIN_SHIFT, 31, 0, eq_tlv), | ||
2131 | SOC_DOUBLE_R_TLV("EQ3 Volume", WM8962_EQ2, WM8962_EQ22, | ||
2132 | WM8962_EQL_B3_GAIN_SHIFT, 31, 0, eq_tlv), | ||
2133 | SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23, | ||
2134 | WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv), | ||
2135 | SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23, | ||
2136 | WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv), | ||
2122 | }; | 2137 | }; |
2123 | 2138 | ||
2124 | static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { | 2139 | static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { |
@@ -2184,6 +2199,8 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, | |||
2184 | struct snd_kcontrol *kcontrol, int event) | 2199 | struct snd_kcontrol *kcontrol, int event) |
2185 | { | 2200 | { |
2186 | struct snd_soc_codec *codec = w->codec; | 2201 | struct snd_soc_codec *codec = w->codec; |
2202 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | ||
2203 | unsigned long timeout; | ||
2187 | int src; | 2204 | int src; |
2188 | int fll; | 2205 | int fll; |
2189 | 2206 | ||
@@ -2203,9 +2220,19 @@ static int sysclk_event(struct snd_soc_dapm_widget *w, | |||
2203 | 2220 | ||
2204 | switch (event) { | 2221 | switch (event) { |
2205 | case SND_SOC_DAPM_PRE_PMU: | 2222 | case SND_SOC_DAPM_PRE_PMU: |
2206 | if (fll) | 2223 | if (fll) { |
2207 | snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, | 2224 | snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, |
2208 | WM8962_FLL_ENA, WM8962_FLL_ENA); | 2225 | WM8962_FLL_ENA, WM8962_FLL_ENA); |
2226 | if (wm8962->irq) { | ||
2227 | timeout = msecs_to_jiffies(5); | ||
2228 | timeout = wait_for_completion_timeout(&wm8962->fll_lock, | ||
2229 | timeout); | ||
2230 | |||
2231 | if (timeout == 0) | ||
2232 | dev_err(codec->dev, | ||
2233 | "Timed out starting FLL\n"); | ||
2234 | } | ||
2235 | } | ||
2209 | break; | 2236 | break; |
2210 | 2237 | ||
2211 | case SND_SOC_DAPM_POST_PMD: | 2238 | case SND_SOC_DAPM_POST_PMD: |
@@ -2763,18 +2790,44 @@ static const int bclk_divs[] = { | |||
2763 | 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32 | 2790 | 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32 |
2764 | }; | 2791 | }; |
2765 | 2792 | ||
2793 | static const int sysclk_rates[] = { | ||
2794 | 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, | ||
2795 | }; | ||
2796 | |||
2766 | static void wm8962_configure_bclk(struct snd_soc_codec *codec) | 2797 | static void wm8962_configure_bclk(struct snd_soc_codec *codec) |
2767 | { | 2798 | { |
2768 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 2799 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
2769 | int dspclk, i; | 2800 | int dspclk, i; |
2770 | int clocking2 = 0; | 2801 | int clocking2 = 0; |
2802 | int clocking4 = 0; | ||
2771 | int aif2 = 0; | 2803 | int aif2 = 0; |
2772 | 2804 | ||
2773 | if (!wm8962->bclk) { | 2805 | if (!wm8962->sysclk_rate) { |
2774 | dev_dbg(codec->dev, "No BCLK rate configured\n"); | 2806 | dev_dbg(codec->dev, "No SYSCLK configured\n"); |
2807 | return; | ||
2808 | } | ||
2809 | |||
2810 | if (!wm8962->bclk || !wm8962->lrclk) { | ||
2811 | dev_dbg(codec->dev, "No audio clocks configured\n"); | ||
2775 | return; | 2812 | return; |
2776 | } | 2813 | } |
2777 | 2814 | ||
2815 | for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { | ||
2816 | if (sysclk_rates[i] == wm8962->sysclk_rate / wm8962->lrclk) { | ||
2817 | clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; | ||
2818 | break; | ||
2819 | } | ||
2820 | } | ||
2821 | |||
2822 | if (i == ARRAY_SIZE(sysclk_rates)) { | ||
2823 | dev_err(codec->dev, "Unsupported sysclk ratio %d\n", | ||
2824 | wm8962->sysclk_rate / wm8962->lrclk); | ||
2825 | return; | ||
2826 | } | ||
2827 | |||
2828 | snd_soc_update_bits(codec, WM8962_CLOCKING_4, | ||
2829 | WM8962_SYSCLK_RATE_MASK, clocking4); | ||
2830 | |||
2778 | dspclk = snd_soc_read(codec, WM8962_CLOCKING1); | 2831 | dspclk = snd_soc_read(codec, WM8962_CLOCKING1); |
2779 | if (dspclk < 0) { | 2832 | if (dspclk < 0) { |
2780 | dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); | 2833 | dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); |
@@ -2844,6 +2897,8 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, | |||
2844 | /* VMID 2*50k */ | 2897 | /* VMID 2*50k */ |
2845 | snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, | 2898 | snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, |
2846 | WM8962_VMID_SEL_MASK, 0x80); | 2899 | WM8962_VMID_SEL_MASK, 0x80); |
2900 | |||
2901 | wm8962_configure_bclk(codec); | ||
2847 | break; | 2902 | break; |
2848 | 2903 | ||
2849 | case SND_SOC_BIAS_STANDBY: | 2904 | case SND_SOC_BIAS_STANDBY: |
@@ -2876,8 +2931,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, | |||
2876 | snd_soc_update_bits(codec, WM8962_CLOCKING2, | 2931 | snd_soc_update_bits(codec, WM8962_CLOCKING2, |
2877 | WM8962_CLKREG_OVD, | 2932 | WM8962_CLKREG_OVD, |
2878 | WM8962_CLKREG_OVD); | 2933 | WM8962_CLKREG_OVD); |
2879 | |||
2880 | wm8962_configure_bclk(codec); | ||
2881 | } | 2934 | } |
2882 | 2935 | ||
2883 | /* VMID 2*250k */ | 2936 | /* VMID 2*250k */ |
@@ -2918,10 +2971,6 @@ static const struct { | |||
2918 | { 96000, 6 }, | 2971 | { 96000, 6 }, |
2919 | }; | 2972 | }; |
2920 | 2973 | ||
2921 | static const int sysclk_rates[] = { | ||
2922 | 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, | ||
2923 | }; | ||
2924 | |||
2925 | static int wm8962_hw_params(struct snd_pcm_substream *substream, | 2974 | static int wm8962_hw_params(struct snd_pcm_substream *substream, |
2926 | struct snd_pcm_hw_params *params, | 2975 | struct snd_pcm_hw_params *params, |
2927 | struct snd_soc_dai *dai) | 2976 | struct snd_soc_dai *dai) |
@@ -2929,41 +2978,27 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, | |||
2929 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 2978 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2930 | struct snd_soc_codec *codec = rtd->codec; | 2979 | struct snd_soc_codec *codec = rtd->codec; |
2931 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 2980 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
2932 | int rate = params_rate(params); | ||
2933 | int i; | 2981 | int i; |
2934 | int aif0 = 0; | 2982 | int aif0 = 0; |
2935 | int adctl3 = 0; | 2983 | int adctl3 = 0; |
2936 | int clocking4 = 0; | ||
2937 | 2984 | ||
2938 | wm8962->bclk = snd_soc_params_to_bclk(params); | 2985 | wm8962->bclk = snd_soc_params_to_bclk(params); |
2939 | wm8962->lrclk = params_rate(params); | 2986 | wm8962->lrclk = params_rate(params); |
2940 | 2987 | ||
2941 | for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { | 2988 | for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { |
2942 | if (sr_vals[i].rate == rate) { | 2989 | if (sr_vals[i].rate == wm8962->lrclk) { |
2943 | adctl3 |= sr_vals[i].reg; | 2990 | adctl3 |= sr_vals[i].reg; |
2944 | break; | 2991 | break; |
2945 | } | 2992 | } |
2946 | } | 2993 | } |
2947 | if (i == ARRAY_SIZE(sr_vals)) { | 2994 | if (i == ARRAY_SIZE(sr_vals)) { |
2948 | dev_err(codec->dev, "Unsupported rate %dHz\n", rate); | 2995 | dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk); |
2949 | return -EINVAL; | 2996 | return -EINVAL; |
2950 | } | 2997 | } |
2951 | 2998 | ||
2952 | if (rate % 8000 == 0) | 2999 | if (wm8962->lrclk % 8000 == 0) |
2953 | adctl3 |= WM8962_SAMPLE_RATE_INT_MODE; | 3000 | adctl3 |= WM8962_SAMPLE_RATE_INT_MODE; |
2954 | 3001 | ||
2955 | for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { | ||
2956 | if (sysclk_rates[i] == wm8962->sysclk_rate / rate) { | ||
2957 | clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; | ||
2958 | break; | ||
2959 | } | ||
2960 | } | ||
2961 | if (i == ARRAY_SIZE(sysclk_rates)) { | ||
2962 | dev_err(codec->dev, "Unsupported sysclk ratio %d\n", | ||
2963 | wm8962->sysclk_rate / rate); | ||
2964 | return -EINVAL; | ||
2965 | } | ||
2966 | |||
2967 | switch (params_format(params)) { | 3002 | switch (params_format(params)) { |
2968 | case SNDRV_PCM_FORMAT_S16_LE: | 3003 | case SNDRV_PCM_FORMAT_S16_LE: |
2969 | break; | 3004 | break; |
@@ -2985,8 +3020,6 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, | |||
2985 | snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, | 3020 | snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, |
2986 | WM8962_SAMPLE_RATE_INT_MODE | | 3021 | WM8962_SAMPLE_RATE_INT_MODE | |
2987 | WM8962_SAMPLE_RATE_MASK, adctl3); | 3022 | WM8962_SAMPLE_RATE_MASK, adctl3); |
2988 | snd_soc_update_bits(codec, WM8962_CLOCKING_4, | ||
2989 | WM8962_SYSCLK_RATE_MASK, clocking4); | ||
2990 | 3023 | ||
2991 | wm8962_configure_bclk(codec); | 3024 | wm8962_configure_bclk(codec); |
2992 | 3025 | ||
@@ -3261,16 +3294,31 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
3261 | 3294 | ||
3262 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); | 3295 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); |
3263 | 3296 | ||
3264 | /* This should be a massive overestimate */ | 3297 | ret = 0; |
3265 | timeout = msecs_to_jiffies(1); | 3298 | |
3299 | if (fll1 & WM8962_FLL_ENA) { | ||
3300 | /* This should be a massive overestimate but go even | ||
3301 | * higher if we'll error out | ||
3302 | */ | ||
3303 | if (wm8962->irq) | ||
3304 | timeout = msecs_to_jiffies(5); | ||
3305 | else | ||
3306 | timeout = msecs_to_jiffies(1); | ||
3307 | |||
3308 | timeout = wait_for_completion_timeout(&wm8962->fll_lock, | ||
3309 | timeout); | ||
3266 | 3310 | ||
3267 | wait_for_completion_timeout(&wm8962->fll_lock, timeout); | 3311 | if (timeout == 0 && wm8962->irq) { |
3312 | dev_err(codec->dev, "FLL lock timed out"); | ||
3313 | ret = -ETIMEDOUT; | ||
3314 | } | ||
3315 | } | ||
3268 | 3316 | ||
3269 | wm8962->fll_fref = Fref; | 3317 | wm8962->fll_fref = Fref; |
3270 | wm8962->fll_fout = Fout; | 3318 | wm8962->fll_fout = Fout; |
3271 | wm8962->fll_src = source; | 3319 | wm8962->fll_src = source; |
3272 | 3320 | ||
3273 | return 0; | 3321 | return ret; |
3274 | } | 3322 | } |
3275 | 3323 | ||
3276 | static int wm8962_mute(struct snd_soc_dai *dai, int mute) | 3324 | static int wm8962_mute(struct snd_soc_dai *dai, int mute) |
@@ -3731,8 +3779,6 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
3731 | int ret; | 3779 | int ret; |
3732 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3780 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
3733 | struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); | 3781 | struct wm8962_pdata *pdata = dev_get_platdata(codec->dev); |
3734 | struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, | ||
3735 | dev); | ||
3736 | u16 *reg_cache = codec->reg_cache; | 3782 | u16 *reg_cache = codec->reg_cache; |
3737 | int i, trigger, irq_pol; | 3783 | int i, trigger, irq_pol; |
3738 | bool dmicclk, dmicdat; | 3784 | bool dmicclk, dmicdat; |
@@ -3871,6 +3917,9 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
3871 | snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, | 3917 | snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, |
3872 | WM8962_HPOUT_VU, WM8962_HPOUT_VU); | 3918 | WM8962_HPOUT_VU, WM8962_HPOUT_VU); |
3873 | 3919 | ||
3920 | /* Stereo control for EQ */ | ||
3921 | snd_soc_update_bits(codec, WM8962_EQ1, WM8962_EQ_SHARED_COEFF, 0); | ||
3922 | |||
3874 | wm8962_add_widgets(codec); | 3923 | wm8962_add_widgets(codec); |
3875 | 3924 | ||
3876 | /* Save boards having to disable DMIC when not in use */ | 3925 | /* Save boards having to disable DMIC when not in use */ |
@@ -3899,7 +3948,7 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
3899 | wm8962_init_beep(codec); | 3948 | wm8962_init_beep(codec); |
3900 | wm8962_init_gpio(codec); | 3949 | wm8962_init_gpio(codec); |
3901 | 3950 | ||
3902 | if (i2c->irq) { | 3951 | if (wm8962->irq) { |
3903 | if (pdata && pdata->irq_active_low) { | 3952 | if (pdata && pdata->irq_active_low) { |
3904 | trigger = IRQF_TRIGGER_LOW; | 3953 | trigger = IRQF_TRIGGER_LOW; |
3905 | irq_pol = WM8962_IRQ_POL; | 3954 | irq_pol = WM8962_IRQ_POL; |
@@ -3911,12 +3960,13 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
3911 | snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, | 3960 | snd_soc_update_bits(codec, WM8962_INTERRUPT_CONTROL, |
3912 | WM8962_IRQ_POL, irq_pol); | 3961 | WM8962_IRQ_POL, irq_pol); |
3913 | 3962 | ||
3914 | ret = request_threaded_irq(i2c->irq, NULL, wm8962_irq, | 3963 | ret = request_threaded_irq(wm8962->irq, NULL, wm8962_irq, |
3915 | trigger | IRQF_ONESHOT, | 3964 | trigger | IRQF_ONESHOT, |
3916 | "wm8962", codec); | 3965 | "wm8962", codec); |
3917 | if (ret != 0) { | 3966 | if (ret != 0) { |
3918 | dev_err(codec->dev, "Failed to request IRQ %d: %d\n", | 3967 | dev_err(codec->dev, "Failed to request IRQ %d: %d\n", |
3919 | i2c->irq, ret); | 3968 | wm8962->irq, ret); |
3969 | wm8962->irq = 0; | ||
3920 | /* Non-fatal */ | 3970 | /* Non-fatal */ |
3921 | } else { | 3971 | } else { |
3922 | /* Enable some IRQs by default */ | 3972 | /* Enable some IRQs by default */ |
@@ -3941,12 +3991,10 @@ err: | |||
3941 | static int wm8962_remove(struct snd_soc_codec *codec) | 3991 | static int wm8962_remove(struct snd_soc_codec *codec) |
3942 | { | 3992 | { |
3943 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3993 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
3944 | struct i2c_client *i2c = container_of(codec->dev, struct i2c_client, | ||
3945 | dev); | ||
3946 | int i; | 3994 | int i; |
3947 | 3995 | ||
3948 | if (i2c->irq) | 3996 | if (wm8962->irq) |
3949 | free_irq(i2c->irq, codec); | 3997 | free_irq(wm8962->irq, codec); |
3950 | 3998 | ||
3951 | cancel_delayed_work_sync(&wm8962->mic_work); | 3999 | cancel_delayed_work_sync(&wm8962->mic_work); |
3952 | 4000 | ||
@@ -3986,6 +4034,8 @@ static __devinit int wm8962_i2c_probe(struct i2c_client *i2c, | |||
3986 | 4034 | ||
3987 | i2c_set_clientdata(i2c, wm8962); | 4035 | i2c_set_clientdata(i2c, wm8962); |
3988 | 4036 | ||
4037 | wm8962->irq = i2c->irq; | ||
4038 | |||
3989 | ret = snd_soc_register_codec(&i2c->dev, | 4039 | ret = snd_soc_register_codec(&i2c->dev, |
3990 | &soc_codec_dev_wm8962, &wm8962_dai, 1); | 4040 | &soc_codec_dev_wm8962, &wm8962_dai, 1); |
3991 | if (ret < 0) | 4041 | if (ret < 0) |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 9e5ff789b805..6e85b8869af7 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -876,7 +876,7 @@ SND_SOC_DAPM_MIXER("SPKL", WM8993_POWER_MANAGEMENT_3, 8, 0, | |||
876 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | 876 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), |
877 | SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0, | 877 | SND_SOC_DAPM_MIXER("SPKR", WM8993_POWER_MANAGEMENT_3, 9, 0, |
878 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | 878 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), |
879 | 879 | SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), | |
880 | }; | 880 | }; |
881 | 881 | ||
882 | static const struct snd_soc_dapm_route routes[] = { | 882 | static const struct snd_soc_dapm_route routes[] = { |
@@ -1434,6 +1434,7 @@ static int wm8993_probe(struct snd_soc_codec *codec) | |||
1434 | 1434 | ||
1435 | wm8993->hubs_data.hp_startup_mode = 1; | 1435 | wm8993->hubs_data.hp_startup_mode = 1; |
1436 | wm8993->hubs_data.dcs_codes = -2; | 1436 | wm8993->hubs_data.dcs_codes = -2; |
1437 | wm8993->hubs_data.series_startup = 1; | ||
1437 | 1438 | ||
1438 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | 1439 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); |
1439 | if (ret != 0) { | 1440 | if (ret != 0) { |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 5f0c238e1783..ee64be2d9942 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -195,10 +195,6 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif) | |||
195 | aif + 1, rate); | 195 | aif + 1, rate); |
196 | } | 196 | } |
197 | 197 | ||
198 | if (rate && rate < 3000000) | ||
199 | dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n", | ||
200 | aif + 1, rate); | ||
201 | |||
202 | wm8994->aifclk[aif] = rate; | 198 | wm8994->aifclk[aif] = rate; |
203 | 199 | ||
204 | snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, | 200 | snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, |
@@ -1146,13 +1142,33 @@ SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, | |||
1146 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | 1142 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), |
1147 | SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, | 1143 | SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, |
1148 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | 1144 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), |
1145 | SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
1146 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1147 | |||
1148 | SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, | ||
1149 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer), | ||
1150 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1151 | SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, | ||
1152 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer), | ||
1153 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1154 | SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux, | ||
1155 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1156 | SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux, | ||
1157 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1149 | 1158 | ||
1150 | SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) | 1159 | SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) |
1151 | }; | 1160 | }; |
1152 | 1161 | ||
1153 | static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { | 1162 | static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { |
1154 | SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), | 1163 | SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), |
1155 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) | 1164 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), |
1165 | SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1166 | SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, | ||
1167 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
1168 | SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, | ||
1169 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
1170 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
1171 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
1156 | }; | 1172 | }; |
1157 | 1173 | ||
1158 | static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { | 1174 | static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { |
@@ -1283,14 +1299,6 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), | |||
1283 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), | 1299 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), |
1284 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), | 1300 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), |
1285 | 1301 | ||
1286 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
1287 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
1288 | |||
1289 | SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, | ||
1290 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
1291 | SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, | ||
1292 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
1293 | |||
1294 | SND_SOC_DAPM_POST("Debug log", post_ev), | 1302 | SND_SOC_DAPM_POST("Debug log", post_ev), |
1295 | }; | 1303 | }; |
1296 | 1304 | ||
@@ -1623,6 +1631,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1623 | int reg_offset, ret; | 1631 | int reg_offset, ret; |
1624 | struct fll_div fll; | 1632 | struct fll_div fll; |
1625 | u16 reg, aif1, aif2; | 1633 | u16 reg, aif1, aif2; |
1634 | unsigned long timeout; | ||
1626 | 1635 | ||
1627 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) | 1636 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) |
1628 | & WM8994_AIF1CLK_ENA; | 1637 | & WM8994_AIF1CLK_ENA; |
@@ -1714,7 +1723,15 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1714 | WM8994_FLL1_ENA | WM8994_FLL1_FRAC, | 1723 | WM8994_FLL1_ENA | WM8994_FLL1_FRAC, |
1715 | reg); | 1724 | reg); |
1716 | 1725 | ||
1717 | msleep(5); | 1726 | if (wm8994->fll_locked_irq) { |
1727 | timeout = wait_for_completion_timeout(&wm8994->fll_locked[id], | ||
1728 | msecs_to_jiffies(10)); | ||
1729 | if (timeout == 0) | ||
1730 | dev_warn(codec->dev, | ||
1731 | "Timed out waiting for FLL lock\n"); | ||
1732 | } else { | ||
1733 | msleep(5); | ||
1734 | } | ||
1718 | } | 1735 | } |
1719 | 1736 | ||
1720 | wm8994->fll[id].in = freq_in; | 1737 | wm8994->fll[id].in = freq_in; |
@@ -1732,6 +1749,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1732 | return 0; | 1749 | return 0; |
1733 | } | 1750 | } |
1734 | 1751 | ||
1752 | static irqreturn_t wm8994_fll_locked_irq(int irq, void *data) | ||
1753 | { | ||
1754 | struct completion *completion = data; | ||
1755 | |||
1756 | complete(completion); | ||
1757 | |||
1758 | return IRQ_HANDLED; | ||
1759 | } | ||
1735 | 1760 | ||
1736 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | 1761 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; |
1737 | 1762 | ||
@@ -2849,6 +2874,15 @@ out: | |||
2849 | return IRQ_HANDLED; | 2874 | return IRQ_HANDLED; |
2850 | } | 2875 | } |
2851 | 2876 | ||
2877 | static irqreturn_t wm8994_fifo_error(int irq, void *data) | ||
2878 | { | ||
2879 | struct snd_soc_codec *codec = data; | ||
2880 | |||
2881 | dev_err(codec->dev, "FIFO error\n"); | ||
2882 | |||
2883 | return IRQ_HANDLED; | ||
2884 | } | ||
2885 | |||
2852 | static int wm8994_codec_probe(struct snd_soc_codec *codec) | 2886 | static int wm8994_codec_probe(struct snd_soc_codec *codec) |
2853 | { | 2887 | { |
2854 | struct wm8994 *control; | 2888 | struct wm8994 *control; |
@@ -2867,6 +2901,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2867 | wm8994->pdata = dev_get_platdata(codec->dev->parent); | 2901 | wm8994->pdata = dev_get_platdata(codec->dev->parent); |
2868 | wm8994->codec = codec; | 2902 | wm8994->codec = codec; |
2869 | 2903 | ||
2904 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | ||
2905 | init_completion(&wm8994->fll_locked[i]); | ||
2906 | |||
2870 | if (wm8994->pdata && wm8994->pdata->micdet_irq) | 2907 | if (wm8994->pdata && wm8994->pdata->micdet_irq) |
2871 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; | 2908 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; |
2872 | else if (wm8994->pdata && wm8994->pdata->irq_base) | 2909 | else if (wm8994->pdata && wm8994->pdata->irq_base) |
@@ -2905,6 +2942,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2905 | wm8994->hubs.dcs_codes = -5; | 2942 | wm8994->hubs.dcs_codes = -5; |
2906 | wm8994->hubs.hp_startup_mode = 1; | 2943 | wm8994->hubs.hp_startup_mode = 1; |
2907 | wm8994->hubs.dcs_readback_mode = 1; | 2944 | wm8994->hubs.dcs_readback_mode = 1; |
2945 | wm8994->hubs.series_startup = 1; | ||
2908 | break; | 2946 | break; |
2909 | default: | 2947 | default: |
2910 | wm8994->hubs.dcs_readback_mode = 1; | 2948 | wm8994->hubs.dcs_readback_mode = 1; |
@@ -2919,6 +2957,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2919 | break; | 2957 | break; |
2920 | } | 2958 | } |
2921 | 2959 | ||
2960 | wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, | ||
2961 | wm8994_fifo_error, "FIFO error", codec); | ||
2962 | |||
2963 | ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE, | ||
2964 | wm_hubs_dcs_done, "DC servo done", | ||
2965 | &wm8994->hubs); | ||
2966 | if (ret == 0) | ||
2967 | wm8994->hubs.dcs_done_irq = true; | ||
2968 | |||
2922 | switch (control->type) { | 2969 | switch (control->type) { |
2923 | case WM8994: | 2970 | case WM8994: |
2924 | if (wm8994->micdet_irq) { | 2971 | if (wm8994->micdet_irq) { |
@@ -2975,6 +3022,16 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2975 | } | 3022 | } |
2976 | } | 3023 | } |
2977 | 3024 | ||
3025 | wm8994->fll_locked_irq = true; | ||
3026 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) { | ||
3027 | ret = wm8994_request_irq(codec->control_data, | ||
3028 | WM8994_IRQ_FLL1_LOCK + i, | ||
3029 | wm8994_fll_locked_irq, "FLL lock", | ||
3030 | &wm8994->fll_locked[i]); | ||
3031 | if (ret != 0) | ||
3032 | wm8994->fll_locked_irq = false; | ||
3033 | } | ||
3034 | |||
2978 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be | 3035 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be |
2979 | * configured on init - if a system wants to do this dynamically | 3036 | * configured on init - if a system wants to do this dynamically |
2980 | * at runtime we can deal with that then. | 3037 | * at runtime we can deal with that then. |
@@ -3050,10 +3107,18 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3050 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, | 3107 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, |
3051 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); | 3108 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); |
3052 | 3109 | ||
3053 | /* Unconditionally enable AIF1 ADC TDM mode; it only affects | 3110 | /* Unconditionally enable AIF1 ADC TDM mode on chips which can |
3054 | * behaviour on idle TDM clock cycles. */ | 3111 | * use this; it only affects behaviour on idle TDM clock |
3055 | snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, | 3112 | * cycles. */ |
3056 | WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); | 3113 | switch (control->type) { |
3114 | case WM8994: | ||
3115 | case WM8958: | ||
3116 | snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, | ||
3117 | WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); | ||
3118 | break; | ||
3119 | default: | ||
3120 | break; | ||
3121 | } | ||
3057 | 3122 | ||
3058 | wm8994_update_class_w(codec); | 3123 | wm8994_update_class_w(codec); |
3059 | 3124 | ||
@@ -3152,6 +3217,12 @@ err_irq: | |||
3152 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); | 3217 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); |
3153 | if (wm8994->micdet_irq) | 3218 | if (wm8994->micdet_irq) |
3154 | free_irq(wm8994->micdet_irq, wm8994); | 3219 | free_irq(wm8994->micdet_irq, wm8994); |
3220 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | ||
3221 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i, | ||
3222 | &wm8994->fll_locked[i]); | ||
3223 | wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, | ||
3224 | &wm8994->hubs); | ||
3225 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); | ||
3155 | err: | 3226 | err: |
3156 | kfree(wm8994); | 3227 | kfree(wm8994); |
3157 | return ret; | 3228 | return ret; |
@@ -3161,11 +3232,20 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3161 | { | 3232 | { |
3162 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3233 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3163 | struct wm8994 *control = codec->control_data; | 3234 | struct wm8994 *control = codec->control_data; |
3235 | int i; | ||
3164 | 3236 | ||
3165 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | 3237 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); |
3166 | 3238 | ||
3167 | pm_runtime_disable(codec->dev); | 3239 | pm_runtime_disable(codec->dev); |
3168 | 3240 | ||
3241 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | ||
3242 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i, | ||
3243 | &wm8994->fll_locked[i]); | ||
3244 | |||
3245 | wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE, | ||
3246 | &wm8994->hubs); | ||
3247 | wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec); | ||
3248 | |||
3169 | switch (control->type) { | 3249 | switch (control->type) { |
3170 | case WM8994: | 3250 | case WM8994: |
3171 | if (wm8994->micdet_irq) | 3251 | if (wm8994->micdet_irq) |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 0a1db04b73bd..1ab2266039f7 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | #include <sound/soc.h> | 12 | #include <sound/soc.h> |
13 | #include <linux/firmware.h> | 13 | #include <linux/firmware.h> |
14 | #include <linux/completion.h> | ||
14 | 15 | ||
15 | #include "wm_hubs.h" | 16 | #include "wm_hubs.h" |
16 | 17 | ||
@@ -79,6 +80,8 @@ struct wm8994_priv { | |||
79 | int mclk[2]; | 80 | int mclk[2]; |
80 | int aifclk[2]; | 81 | int aifclk[2]; |
81 | struct wm8994_fll_config fll[2], fll_suspend[2]; | 82 | struct wm8994_fll_config fll[2], fll_suspend[2]; |
83 | struct completion fll_locked[2]; | ||
84 | bool fll_locked_irq; | ||
82 | 85 | ||
83 | int dac_rates[2]; | 86 | int dac_rates[2]; |
84 | int lrclk_shared[2]; | 87 | int lrclk_shared[2]; |
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 91c6b39de50c..a4691321f9b3 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -727,7 +727,7 @@ SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0, | |||
727 | SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), | 727 | SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), |
728 | 728 | ||
729 | SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0), | 729 | SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0), |
730 | SND_SOC_DAPM_PGA("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), | 730 | SND_SOC_DAPM_OUT_DRV("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), |
731 | 731 | ||
732 | SND_SOC_DAPM_OUTPUT("LINEOUT"), | 732 | SND_SOC_DAPM_OUTPUT("LINEOUT"), |
733 | SND_SOC_DAPM_OUTPUT("SPKN"), | 733 | SND_SOC_DAPM_OUTPUT("SPKN"), |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 9e370d14ad88..5c2d5657b472 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -63,9 +63,11 @@ static const struct soc_enum speaker_mode = | |||
63 | 63 | ||
64 | static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) | 64 | static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) |
65 | { | 65 | { |
66 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | ||
66 | unsigned int reg; | 67 | unsigned int reg; |
67 | int count = 0; | 68 | int count = 0; |
68 | unsigned int val; | 69 | unsigned int val; |
70 | unsigned long timeout; | ||
69 | 71 | ||
70 | val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1; | 72 | val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1; |
71 | 73 | ||
@@ -74,18 +76,37 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) | |||
74 | 76 | ||
75 | dev_dbg(codec->dev, "Waiting for DC servo...\n"); | 77 | dev_dbg(codec->dev, "Waiting for DC servo...\n"); |
76 | 78 | ||
77 | do { | 79 | if (hubs->dcs_done_irq) { |
78 | count++; | 80 | timeout = wait_for_completion_timeout(&hubs->dcs_done, |
79 | msleep(1); | 81 | msecs_to_jiffies(500)); |
82 | if (timeout == 0) | ||
83 | dev_warn(codec->dev, "No DC servo interrupt\n"); | ||
84 | |||
80 | reg = snd_soc_read(codec, WM8993_DC_SERVO_0); | 85 | reg = snd_soc_read(codec, WM8993_DC_SERVO_0); |
81 | dev_dbg(codec->dev, "DC servo: %x\n", reg); | 86 | } else { |
82 | } while (reg & op && count < 400); | 87 | do { |
88 | count++; | ||
89 | msleep(1); | ||
90 | reg = snd_soc_read(codec, WM8993_DC_SERVO_0); | ||
91 | dev_dbg(codec->dev, "DC servo: %x\n", reg); | ||
92 | } while (reg & op && count < 400); | ||
93 | } | ||
83 | 94 | ||
84 | if (reg & op) | 95 | if (reg & op) |
85 | dev_err(codec->dev, "Timed out waiting for DC Servo %x\n", | 96 | dev_err(codec->dev, "Timed out waiting for DC Servo %x\n", |
86 | op); | 97 | op); |
87 | } | 98 | } |
88 | 99 | ||
100 | irqreturn_t wm_hubs_dcs_done(int irq, void *data) | ||
101 | { | ||
102 | struct wm_hubs_data *hubs = data; | ||
103 | |||
104 | complete(&hubs->dcs_done); | ||
105 | |||
106 | return IRQ_HANDLED; | ||
107 | } | ||
108 | EXPORT_SYMBOL_GPL(wm_hubs_dcs_done); | ||
109 | |||
89 | /* | 110 | /* |
90 | * Startup calibration of the DC servo | 111 | * Startup calibration of the DC servo |
91 | */ | 112 | */ |
@@ -107,8 +128,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) | |||
107 | return; | 128 | return; |
108 | } | 129 | } |
109 | 130 | ||
110 | /* Devices not using a DCS code correction have startup mode */ | 131 | if (hubs->series_startup) { |
111 | if (hubs->dcs_codes) { | ||
112 | /* Set for 32 series updates */ | 132 | /* Set for 32 series updates */ |
113 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, | 133 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, |
114 | WM8993_DCS_SERIES_NO_01_MASK, | 134 | WM8993_DCS_SERIES_NO_01_MASK, |
@@ -134,9 +154,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) | |||
134 | break; | 154 | break; |
135 | case 1: | 155 | case 1: |
136 | reg = snd_soc_read(codec, WM8993_DC_SERVO_3); | 156 | reg = snd_soc_read(codec, WM8993_DC_SERVO_3); |
137 | reg_l = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) | 157 | reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK) |
138 | >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; | 158 | >> WM8993_DCS_DAC_WR_VAL_1_SHIFT; |
139 | reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; | 159 | reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK; |
140 | break; | 160 | break; |
141 | default: | 161 | default: |
142 | WARN(1, "Unknown DCS readback method\n"); | 162 | WARN(1, "Unknown DCS readback method\n"); |
@@ -150,13 +170,13 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) | |||
150 | dev_dbg(codec->dev, "Applying %d code DC servo correction\n", | 170 | dev_dbg(codec->dev, "Applying %d code DC servo correction\n", |
151 | hubs->dcs_codes); | 171 | hubs->dcs_codes); |
152 | 172 | ||
153 | /* HPOUT1L */ | 173 | /* HPOUT1R */ |
154 | offset = reg_l; | 174 | offset = reg_r; |
155 | offset += hubs->dcs_codes; | 175 | offset += hubs->dcs_codes; |
156 | dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT; | 176 | dcs_cfg = (u8)offset << WM8993_DCS_DAC_WR_VAL_1_SHIFT; |
157 | 177 | ||
158 | /* HPOUT1R */ | 178 | /* HPOUT1L */ |
159 | offset = reg_r; | 179 | offset = reg_l; |
160 | offset += hubs->dcs_codes; | 180 | offset += hubs->dcs_codes; |
161 | dcs_cfg |= (u8)offset; | 181 | dcs_cfg |= (u8)offset; |
162 | 182 | ||
@@ -168,8 +188,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec) | |||
168 | WM8993_DCS_TRIG_DAC_WR_0 | | 188 | WM8993_DCS_TRIG_DAC_WR_0 | |
169 | WM8993_DCS_TRIG_DAC_WR_1); | 189 | WM8993_DCS_TRIG_DAC_WR_1); |
170 | } else { | 190 | } else { |
171 | dcs_cfg = reg_l << WM8993_DCS_DAC_WR_VAL_1_SHIFT; | 191 | dcs_cfg = reg_r << WM8993_DCS_DAC_WR_VAL_1_SHIFT; |
172 | dcs_cfg |= reg_r; | 192 | dcs_cfg |= reg_l; |
173 | } | 193 | } |
174 | 194 | ||
175 | /* Save the callibrated offset if we're in class W mode and | 195 | /* Save the callibrated offset if we're in class W mode and |
@@ -195,7 +215,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol, | |||
195 | 215 | ||
196 | /* If we're applying an offset correction then updating the | 216 | /* If we're applying an offset correction then updating the |
197 | * callibration would be likely to introduce further offsets. */ | 217 | * callibration would be likely to introduce further offsets. */ |
198 | if (hubs->dcs_codes) | 218 | if (hubs->dcs_codes || hubs->no_series_update) |
199 | return ret; | 219 | return ret; |
200 | 220 | ||
201 | /* Only need to do this if the outputs are active */ | 221 | /* Only need to do this if the outputs are active */ |
@@ -599,9 +619,6 @@ SND_SOC_DAPM_MIXER("IN2L PGA", WM8993_POWER_MANAGEMENT_2, 7, 0, | |||
599 | SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, | 619 | SND_SOC_DAPM_MIXER("IN2R PGA", WM8993_POWER_MANAGEMENT_2, 5, 0, |
600 | in2r_pga, ARRAY_SIZE(in2r_pga)), | 620 | in2r_pga, ARRAY_SIZE(in2r_pga)), |
601 | 621 | ||
602 | /* Dummy widgets to represent differential paths */ | ||
603 | SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
604 | |||
605 | SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, | 622 | SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, |
606 | mixinl, ARRAY_SIZE(mixinl)), | 623 | mixinl, ARRAY_SIZE(mixinl)), |
607 | SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, | 624 | SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, |
@@ -867,8 +884,11 @@ EXPORT_SYMBOL_GPL(wm_hubs_add_analogue_controls); | |||
867 | int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, | 884 | int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec, |
868 | int lineout1_diff, int lineout2_diff) | 885 | int lineout1_diff, int lineout2_diff) |
869 | { | 886 | { |
887 | struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec); | ||
870 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 888 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
871 | 889 | ||
890 | init_completion(&hubs->dcs_done); | ||
891 | |||
872 | snd_soc_dapm_add_routes(dapm, analogue_routes, | 892 | snd_soc_dapm_add_routes(dapm, analogue_routes, |
873 | ARRAY_SIZE(analogue_routes)); | 893 | ARRAY_SIZE(analogue_routes)); |
874 | 894 | ||
diff --git a/sound/soc/codecs/wm_hubs.h b/sound/soc/codecs/wm_hubs.h index f8a5e976b5e6..676b1252ab91 100644 --- a/sound/soc/codecs/wm_hubs.h +++ b/sound/soc/codecs/wm_hubs.h | |||
@@ -14,6 +14,9 @@ | |||
14 | #ifndef _WM_HUBS_H | 14 | #ifndef _WM_HUBS_H |
15 | #define _WM_HUBS_H | 15 | #define _WM_HUBS_H |
16 | 16 | ||
17 | #include <linux/completion.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | |||
17 | struct snd_soc_codec; | 20 | struct snd_soc_codec; |
18 | 21 | ||
19 | extern const unsigned int wm_hubs_spkmix_tlv[]; | 22 | extern const unsigned int wm_hubs_spkmix_tlv[]; |
@@ -23,9 +26,14 @@ struct wm_hubs_data { | |||
23 | int dcs_codes; | 26 | int dcs_codes; |
24 | int dcs_readback_mode; | 27 | int dcs_readback_mode; |
25 | int hp_startup_mode; | 28 | int hp_startup_mode; |
29 | int series_startup; | ||
30 | int no_series_update; | ||
26 | 31 | ||
27 | bool class_w; | 32 | bool class_w; |
28 | u16 class_w_dcs; | 33 | u16 class_w_dcs; |
34 | |||
35 | bool dcs_done_irq; | ||
36 | struct completion dcs_done; | ||
29 | }; | 37 | }; |
30 | 38 | ||
31 | extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); | 39 | extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *); |
@@ -36,4 +44,6 @@ extern int wm_hubs_handle_analogue_pdata(struct snd_soc_codec *, | |||
36 | int jd_scthr, int jd_thr, | 44 | int jd_scthr, int jd_thr, |
37 | int micbias1_lvl, int micbias2_lvl); | 45 | int micbias1_lvl, int micbias2_lvl); |
38 | 46 | ||
47 | extern irqreturn_t wm_hubs_dcs_done(int irq, void *data); | ||
48 | |||
39 | #endif | 49 | #endif |
diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 9d35b8c1a624..a49e667373bc 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c | |||
@@ -46,11 +46,28 @@ static void print_buf_info(int slot, char *name) | |||
46 | } | 46 | } |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #define DAVINCI_PCM_FMTBITS (\ | ||
50 | SNDRV_PCM_FMTBIT_S8 |\ | ||
51 | SNDRV_PCM_FMTBIT_U8 |\ | ||
52 | SNDRV_PCM_FMTBIT_S16_LE |\ | ||
53 | SNDRV_PCM_FMTBIT_S16_BE |\ | ||
54 | SNDRV_PCM_FMTBIT_U16_LE |\ | ||
55 | SNDRV_PCM_FMTBIT_U16_BE |\ | ||
56 | SNDRV_PCM_FMTBIT_S24_LE |\ | ||
57 | SNDRV_PCM_FMTBIT_S24_BE |\ | ||
58 | SNDRV_PCM_FMTBIT_U24_LE |\ | ||
59 | SNDRV_PCM_FMTBIT_U24_BE |\ | ||
60 | SNDRV_PCM_FMTBIT_S32_LE |\ | ||
61 | SNDRV_PCM_FMTBIT_S32_BE |\ | ||
62 | SNDRV_PCM_FMTBIT_U32_LE |\ | ||
63 | SNDRV_PCM_FMTBIT_U32_BE) | ||
64 | |||
49 | static struct snd_pcm_hardware pcm_hardware_playback = { | 65 | static struct snd_pcm_hardware pcm_hardware_playback = { |
50 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 66 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
51 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | 67 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | |
52 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), | 68 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| |
53 | .formats = (SNDRV_PCM_FMTBIT_S16_LE), | 69 | SNDRV_PCM_INFO_BATCH), |
70 | .formats = DAVINCI_PCM_FMTBITS, | ||
54 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | | 71 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | |
55 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | | 72 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | |
56 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | 73 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
@@ -59,7 +76,7 @@ static struct snd_pcm_hardware pcm_hardware_playback = { | |||
59 | .rate_min = 8000, | 76 | .rate_min = 8000, |
60 | .rate_max = 96000, | 77 | .rate_max = 96000, |
61 | .channels_min = 2, | 78 | .channels_min = 2, |
62 | .channels_max = 2, | 79 | .channels_max = 384, |
63 | .buffer_bytes_max = 128 * 1024, | 80 | .buffer_bytes_max = 128 * 1024, |
64 | .period_bytes_min = 32, | 81 | .period_bytes_min = 32, |
65 | .period_bytes_max = 8 * 1024, | 82 | .period_bytes_max = 8 * 1024, |
@@ -71,8 +88,9 @@ static struct snd_pcm_hardware pcm_hardware_playback = { | |||
71 | static struct snd_pcm_hardware pcm_hardware_capture = { | 88 | static struct snd_pcm_hardware pcm_hardware_capture = { |
72 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 89 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
73 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | 90 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | |
74 | SNDRV_PCM_INFO_PAUSE), | 91 | SNDRV_PCM_INFO_PAUSE | |
75 | .formats = (SNDRV_PCM_FMTBIT_S16_LE), | 92 | SNDRV_PCM_INFO_BATCH), |
93 | .formats = DAVINCI_PCM_FMTBITS, | ||
76 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | | 94 | .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | |
77 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | | 95 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | |
78 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | | 96 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | |
@@ -81,7 +99,7 @@ static struct snd_pcm_hardware pcm_hardware_capture = { | |||
81 | .rate_min = 8000, | 99 | .rate_min = 8000, |
82 | .rate_max = 96000, | 100 | .rate_max = 96000, |
83 | .channels_min = 2, | 101 | .channels_min = 2, |
84 | .channels_max = 2, | 102 | .channels_max = 384, |
85 | .buffer_bytes_max = 128 * 1024, | 103 | .buffer_bytes_max = 128 * 1024, |
86 | .period_bytes_min = 32, | 104 | .period_bytes_min = 32, |
87 | .period_bytes_max = 8 * 1024, | 105 | .period_bytes_max = 8 * 1024, |
@@ -139,6 +157,22 @@ struct davinci_runtime_data { | |||
139 | struct edmacc_param ram_params; | 157 | struct edmacc_param ram_params; |
140 | }; | 158 | }; |
141 | 159 | ||
160 | static void davinci_pcm_period_elapsed(struct snd_pcm_substream *substream) | ||
161 | { | ||
162 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | ||
163 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
164 | |||
165 | prtd->period++; | ||
166 | if (unlikely(prtd->period >= runtime->periods)) | ||
167 | prtd->period = 0; | ||
168 | } | ||
169 | |||
170 | static void davinci_pcm_period_reset(struct snd_pcm_substream *substream) | ||
171 | { | ||
172 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | ||
173 | |||
174 | prtd->period = 0; | ||
175 | } | ||
142 | /* | 176 | /* |
143 | * Not used with ping/pong | 177 | * Not used with ping/pong |
144 | */ | 178 | */ |
@@ -199,10 +233,6 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) | |||
199 | else | 233 | else |
200 | edma_set_transfer_params(link, acnt, fifo_level, count, | 234 | edma_set_transfer_params(link, acnt, fifo_level, count, |
201 | fifo_level, ABSYNC); | 235 | fifo_level, ABSYNC); |
202 | |||
203 | prtd->period++; | ||
204 | if (unlikely(prtd->period >= runtime->periods)) | ||
205 | prtd->period = 0; | ||
206 | } | 236 | } |
207 | 237 | ||
208 | static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) | 238 | static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) |
@@ -217,12 +247,13 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) | |||
217 | return; | 247 | return; |
218 | 248 | ||
219 | if (snd_pcm_running(substream)) { | 249 | if (snd_pcm_running(substream)) { |
250 | spin_lock(&prtd->lock); | ||
220 | if (prtd->ram_channel < 0) { | 251 | if (prtd->ram_channel < 0) { |
221 | /* No ping/pong must fix up link dma data*/ | 252 | /* No ping/pong must fix up link dma data*/ |
222 | spin_lock(&prtd->lock); | ||
223 | davinci_pcm_enqueue_dma(substream); | 253 | davinci_pcm_enqueue_dma(substream); |
224 | spin_unlock(&prtd->lock); | ||
225 | } | 254 | } |
255 | davinci_pcm_period_elapsed(substream); | ||
256 | spin_unlock(&prtd->lock); | ||
226 | snd_pcm_period_elapsed(substream); | 257 | snd_pcm_period_elapsed(substream); |
227 | } | 258 | } |
228 | } | 259 | } |
@@ -425,7 +456,8 @@ static int request_ping_pong(struct snd_pcm_substream *substream, | |||
425 | 456 | ||
426 | edma_read_slot(link, &prtd->asp_params); | 457 | edma_read_slot(link, &prtd->asp_params); |
427 | prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); | 458 | prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f) | TCINTEN); |
428 | prtd->asp_params.opt |= TCCHEN | EDMA_TCC(prtd->ram_channel & 0x3f); | 459 | prtd->asp_params.opt |= TCCHEN | |
460 | EDMA_TCC(prtd->ram_channel & 0x3f); | ||
429 | edma_write_slot(link, &prtd->asp_params); | 461 | edma_write_slot(link, &prtd->asp_params); |
430 | 462 | ||
431 | /* pong */ | 463 | /* pong */ |
@@ -439,7 +471,7 @@ static int request_ping_pong(struct snd_pcm_substream *substream, | |||
439 | prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); | 471 | prtd->asp_params.opt &= ~(TCCMODE | EDMA_TCC(0x3f)); |
440 | /* interrupt after every pong completion */ | 472 | /* interrupt after every pong completion */ |
441 | prtd->asp_params.opt |= TCINTEN | TCCHEN | | 473 | prtd->asp_params.opt |= TCINTEN | TCCHEN | |
442 | EDMA_TCC(EDMA_CHAN_SLOT(prtd->ram_channel)); | 474 | EDMA_TCC(prtd->ram_channel & 0x3f); |
443 | edma_write_slot(link, &prtd->asp_params); | 475 | edma_write_slot(link, &prtd->asp_params); |
444 | 476 | ||
445 | /* ram */ | 477 | /* ram */ |
@@ -527,6 +559,13 @@ static int davinci_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
527 | 559 | ||
528 | switch (cmd) { | 560 | switch (cmd) { |
529 | case SNDRV_PCM_TRIGGER_START: | 561 | case SNDRV_PCM_TRIGGER_START: |
562 | edma_start(prtd->asp_channel); | ||
563 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
564 | prtd->ram_channel >= 0) { | ||
565 | /* copy 1st iram buffer */ | ||
566 | edma_start(prtd->ram_channel); | ||
567 | } | ||
568 | break; | ||
530 | case SNDRV_PCM_TRIGGER_RESUME: | 569 | case SNDRV_PCM_TRIGGER_RESUME: |
531 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 570 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
532 | edma_resume(prtd->asp_channel); | 571 | edma_resume(prtd->asp_channel); |
@@ -550,6 +589,7 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) | |||
550 | { | 589 | { |
551 | struct davinci_runtime_data *prtd = substream->runtime->private_data; | 590 | struct davinci_runtime_data *prtd = substream->runtime->private_data; |
552 | 591 | ||
592 | davinci_pcm_period_reset(substream); | ||
553 | if (prtd->ram_channel >= 0) { | 593 | if (prtd->ram_channel >= 0) { |
554 | int ret = ping_pong_dma_setup(substream); | 594 | int ret = ping_pong_dma_setup(substream); |
555 | if (ret < 0) | 595 | if (ret < 0) |
@@ -565,21 +605,31 @@ static int davinci_pcm_prepare(struct snd_pcm_substream *substream) | |||
565 | print_buf_info(prtd->asp_link[0], "asp_link[0]"); | 605 | print_buf_info(prtd->asp_link[0], "asp_link[0]"); |
566 | print_buf_info(prtd->asp_link[1], "asp_link[1]"); | 606 | print_buf_info(prtd->asp_link[1], "asp_link[1]"); |
567 | 607 | ||
568 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 608 | /* |
569 | /* copy 1st iram buffer */ | 609 | * There is a phase offset of 2 periods between the position |
570 | edma_start(prtd->ram_channel); | 610 | * used by dma setup and the position reported in the pointer |
571 | } | 611 | * function. |
572 | edma_start(prtd->asp_channel); | 612 | * |
613 | * The phase offset, when not using ping-pong buffers, is due to | ||
614 | * the two consecutive calls to davinci_pcm_enqueue_dma() below. | ||
615 | * | ||
616 | * Whereas here, with ping-pong buffers, the phase is due to | ||
617 | * there being an entire buffer transfer complete before the | ||
618 | * first dma completion event triggers davinci_pcm_dma_irq(). | ||
619 | */ | ||
620 | davinci_pcm_period_elapsed(substream); | ||
621 | davinci_pcm_period_elapsed(substream); | ||
622 | |||
573 | return 0; | 623 | return 0; |
574 | } | 624 | } |
575 | prtd->period = 0; | ||
576 | davinci_pcm_enqueue_dma(substream); | 625 | davinci_pcm_enqueue_dma(substream); |
626 | davinci_pcm_period_elapsed(substream); | ||
577 | 627 | ||
578 | /* Copy self-linked parameter RAM entry into master channel */ | 628 | /* Copy self-linked parameter RAM entry into master channel */ |
579 | edma_read_slot(prtd->asp_link[0], &prtd->asp_params); | 629 | edma_read_slot(prtd->asp_link[0], &prtd->asp_params); |
580 | edma_write_slot(prtd->asp_channel, &prtd->asp_params); | 630 | edma_write_slot(prtd->asp_channel, &prtd->asp_params); |
581 | davinci_pcm_enqueue_dma(substream); | 631 | davinci_pcm_enqueue_dma(substream); |
582 | edma_start(prtd->asp_channel); | 632 | davinci_pcm_period_elapsed(substream); |
583 | 633 | ||
584 | return 0; | 634 | return 0; |
585 | } | 635 | } |
@@ -591,51 +641,23 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) | |||
591 | struct davinci_runtime_data *prtd = runtime->private_data; | 641 | struct davinci_runtime_data *prtd = runtime->private_data; |
592 | unsigned int offset; | 642 | unsigned int offset; |
593 | int asp_count; | 643 | int asp_count; |
594 | dma_addr_t asp_src, asp_dst; | 644 | unsigned int period_size = snd_pcm_lib_period_bytes(substream); |
595 | 645 | ||
646 | /* | ||
647 | * There is a phase offset of 2 periods between the position used by dma | ||
648 | * setup and the position reported in the pointer function. Either +2 in | ||
649 | * the dma setup or -2 here in the pointer function (with wrapping, | ||
650 | * both) accounts for this offset -- choose the latter since it makes | ||
651 | * the first-time setup clearer. | ||
652 | */ | ||
596 | spin_lock(&prtd->lock); | 653 | spin_lock(&prtd->lock); |
597 | if (prtd->ram_channel >= 0) { | 654 | asp_count = prtd->period - 2; |
598 | int ram_count; | ||
599 | int mod_ram; | ||
600 | dma_addr_t ram_src, ram_dst; | ||
601 | unsigned int period_size = snd_pcm_lib_period_bytes(substream); | ||
602 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
603 | /* reading ram before asp should be safe | ||
604 | * as long as the asp transfers less than a ping size | ||
605 | * of bytes between the 2 reads | ||
606 | */ | ||
607 | edma_get_position(prtd->ram_channel, | ||
608 | &ram_src, &ram_dst); | ||
609 | edma_get_position(prtd->asp_channel, | ||
610 | &asp_src, &asp_dst); | ||
611 | asp_count = asp_src - prtd->asp_params.src; | ||
612 | ram_count = ram_src - prtd->ram_params.src; | ||
613 | mod_ram = ram_count % period_size; | ||
614 | mod_ram -= asp_count; | ||
615 | if (mod_ram < 0) | ||
616 | mod_ram += period_size; | ||
617 | else if (mod_ram == 0) { | ||
618 | if (snd_pcm_running(substream)) | ||
619 | mod_ram += period_size; | ||
620 | } | ||
621 | ram_count -= mod_ram; | ||
622 | if (ram_count < 0) | ||
623 | ram_count += period_size * runtime->periods; | ||
624 | } else { | ||
625 | edma_get_position(prtd->ram_channel, | ||
626 | &ram_src, &ram_dst); | ||
627 | ram_count = ram_dst - prtd->ram_params.dst; | ||
628 | } | ||
629 | asp_count = ram_count; | ||
630 | } else { | ||
631 | edma_get_position(prtd->asp_channel, &asp_src, &asp_dst); | ||
632 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
633 | asp_count = asp_src - runtime->dma_addr; | ||
634 | else | ||
635 | asp_count = asp_dst - runtime->dma_addr; | ||
636 | } | ||
637 | spin_unlock(&prtd->lock); | 655 | spin_unlock(&prtd->lock); |
638 | 656 | ||
657 | if (asp_count < 0) | ||
658 | asp_count += runtime->periods; | ||
659 | asp_count *= period_size; | ||
660 | |||
639 | offset = bytes_to_frames(runtime, asp_count); | 661 | offset = bytes_to_frames(runtime, asp_count); |
640 | if (offset >= runtime->buffer_size) | 662 | if (offset >= runtime->buffer_size) |
641 | offset = 0; | 663 | offset = 0; |
@@ -811,9 +833,11 @@ static void davinci_pcm_free(struct snd_pcm *pcm) | |||
811 | 833 | ||
812 | static u64 davinci_pcm_dmamask = 0xffffffff; | 834 | static u64 davinci_pcm_dmamask = 0xffffffff; |
813 | 835 | ||
814 | static int davinci_pcm_new(struct snd_card *card, | 836 | static int davinci_pcm_new(struct snd_soc_pcm_runtime *rtd) |
815 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
816 | { | 837 | { |
838 | struct snd_card *card = rtd->card->snd_card; | ||
839 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
840 | struct snd_pcm *pcm = rtd->pcm; | ||
817 | int ret; | 841 | int ret; |
818 | 842 | ||
819 | if (!card->dev->dma_mask) | 843 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index a456e491155f..e27c417da437 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c | |||
@@ -266,9 +266,11 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
266 | 266 | ||
267 | static u64 ep93xx_pcm_dmamask = 0xffffffff; | 267 | static u64 ep93xx_pcm_dmamask = 0xffffffff; |
268 | 268 | ||
269 | static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 269 | static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd) |
270 | struct snd_pcm *pcm) | ||
271 | { | 270 | { |
271 | struct snd_card *card = rtd->card->snd_card; | ||
272 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
273 | struct snd_pcm *pcm = rtd->pcm; | ||
272 | int ret = 0; | 274 | int ret = 0; |
273 | 275 | ||
274 | if (!card->dev->dma_mask) | 276 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c index 6680c0b4d203..732208c8c0b4 100644 --- a/sound/soc/fsl/fsl_dma.c +++ b/sound/soc/fsl/fsl_dma.c | |||
@@ -294,9 +294,11 @@ static irqreturn_t fsl_dma_isr(int irq, void *dev_id) | |||
294 | * Regardless of where the memory is actually allocated, since the device can | 294 | * Regardless of where the memory is actually allocated, since the device can |
295 | * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. | 295 | * technically DMA to any 36-bit address, we do need to set the DMA mask to 36. |
296 | */ | 296 | */ |
297 | static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai, | 297 | static int fsl_dma_new(struct snd_soc_pcm_runtime *rtd) |
298 | struct snd_pcm *pcm) | ||
299 | { | 298 | { |
299 | struct snd_card *card = rtd->card->snd_card; | ||
300 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
301 | struct snd_pcm *pcm = rtd->pcm; | ||
300 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(36); | 302 | static u64 fsl_dma_dmamask = DMA_BIT_MASK(36); |
301 | int ret; | 303 | int ret; |
302 | 304 | ||
@@ -939,7 +941,7 @@ static int __devinit fsl_soc_dma_probe(struct platform_device *pdev) | |||
939 | 941 | ||
940 | iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); | 942 | iprop = of_get_property(ssi_np, "fsl,fifo-depth", NULL); |
941 | if (iprop) | 943 | if (iprop) |
942 | dma->ssi_fifo_depth = *iprop; | 944 | dma->ssi_fifo_depth = be32_to_cpup(iprop); |
943 | else | 945 | else |
944 | /* Older 8610 DTs didn't have the fifo-depth property */ | 946 | /* Older 8610 DTs didn't have the fifo-depth property */ |
945 | dma->ssi_fifo_depth = 8; | 947 | dma->ssi_fifo_depth = 8; |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 313e0ccedd5b..d48afea5d93d 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -678,7 +678,12 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) | |||
678 | kfree(ssi_private); | 678 | kfree(ssi_private); |
679 | return ret; | 679 | return ret; |
680 | } | 680 | } |
681 | ssi_private->ssi = ioremap(res.start, 1 + res.end - res.start); | 681 | ssi_private->ssi = of_iomap(np, 0); |
682 | if (!ssi_private->ssi) { | ||
683 | dev_err(&pdev->dev, "could not map device resources\n"); | ||
684 | kfree(ssi_private); | ||
685 | return -ENOMEM; | ||
686 | } | ||
682 | ssi_private->ssi_phys = res.start; | 687 | ssi_private->ssi_phys = res.start; |
683 | ssi_private->irq = irq_of_parse_and_map(np, 0); | 688 | ssi_private->irq = irq_of_parse_and_map(np, 0); |
684 | 689 | ||
@@ -691,7 +696,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) | |||
691 | /* Determine the FIFO depth. */ | 696 | /* Determine the FIFO depth. */ |
692 | iprop = of_get_property(np, "fsl,fifo-depth", NULL); | 697 | iprop = of_get_property(np, "fsl,fifo-depth", NULL); |
693 | if (iprop) | 698 | if (iprop) |
694 | ssi_private->fifo_depth = *iprop; | 699 | ssi_private->fifo_depth = be32_to_cpup(iprop); |
695 | else | 700 | else |
696 | /* Older 8610 DTs didn't have the fifo-depth property */ | 701 | /* Older 8610 DTs didn't have the fifo-depth property */ |
697 | ssi_private->fifo_depth = 8; | 702 | ssi_private->fifo_depth = 8; |
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index fff695ccdd3e..19ad0c1be67e 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c | |||
@@ -299,10 +299,11 @@ static struct snd_pcm_ops psc_dma_ops = { | |||
299 | }; | 299 | }; |
300 | 300 | ||
301 | static u64 psc_dma_dmamask = 0xffffffff; | 301 | static u64 psc_dma_dmamask = 0xffffffff; |
302 | static int psc_dma_new(struct snd_card *card, struct snd_soc_dai *dai, | 302 | static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) |
303 | struct snd_pcm *pcm) | ||
304 | { | 303 | { |
305 | struct snd_soc_pcm_runtime *rtd = pcm->private_data; | 304 | struct snd_card *card = rtd->card->snd_card; |
305 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
306 | struct snd_pcm *pcm = rtd->pcm; | ||
306 | struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); | 307 | struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai); |
307 | size_t size = psc_dma_hardware.buffer_bytes_max; | 308 | size_t size = psc_dma_hardware.buffer_bytes_max; |
308 | int rc = 0; | 309 | int rc = 0; |
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index c16c6b2eff95..a19297959587 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -233,7 +233,7 @@ static int get_parent_cell_index(struct device_node *np) | |||
233 | if (!iprop) | 233 | if (!iprop) |
234 | return -1; | 234 | return -1; |
235 | 235 | ||
236 | return *iprop; | 236 | return be32_to_cpup(iprop); |
237 | } | 237 | } |
238 | 238 | ||
239 | /** | 239 | /** |
@@ -258,7 +258,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) | |||
258 | if (!iprop) | 258 | if (!iprop) |
259 | return -EINVAL; | 259 | return -EINVAL; |
260 | 260 | ||
261 | addr = *iprop; | 261 | addr = be32_to_cpup(iprop); |
262 | 262 | ||
263 | bus = get_parent_cell_index(np); | 263 | bus = get_parent_cell_index(np); |
264 | if (bus < 0) | 264 | if (bus < 0) |
@@ -305,7 +305,7 @@ static int get_dma_channel(struct device_node *ssi_np, | |||
305 | return -EINVAL; | 305 | return -EINVAL; |
306 | } | 306 | } |
307 | 307 | ||
308 | *dma_channel_id = *iprop; | 308 | *dma_channel_id = be32_to_cpup(iprop); |
309 | *dma_id = get_parent_cell_index(dma_channel_np); | 309 | *dma_id = get_parent_cell_index(dma_channel_np); |
310 | of_node_put(dma_channel_np); | 310 | of_node_put(dma_channel_np); |
311 | 311 | ||
@@ -379,7 +379,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) | |||
379 | ret = -EINVAL; | 379 | ret = -EINVAL; |
380 | goto error; | 380 | goto error; |
381 | } | 381 | } |
382 | machine_data->ssi_id = *iprop; | 382 | machine_data->ssi_id = be32_to_cpup(iprop); |
383 | 383 | ||
384 | /* Get the serial format and clock direction. */ | 384 | /* Get the serial format and clock direction. */ |
385 | sprop = of_get_property(np, "fsl,mode", NULL); | 385 | sprop = of_get_property(np, "fsl,mode", NULL); |
@@ -405,7 +405,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) | |||
405 | ret = -EINVAL; | 405 | ret = -EINVAL; |
406 | goto error; | 406 | goto error; |
407 | } | 407 | } |
408 | machine_data->clk_frequency = *iprop; | 408 | machine_data->clk_frequency = be32_to_cpup(iprop); |
409 | } else if (strcasecmp(sprop, "i2s-master") == 0) { | 409 | } else if (strcasecmp(sprop, "i2s-master") == 0) { |
410 | machine_data->dai_format = SND_SOC_DAIFMT_I2S; | 410 | machine_data->dai_format = SND_SOC_DAIFMT_I2S; |
411 | machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; | 411 | machine_data->codec_clk_direction = SND_SOC_CLOCK_IN; |
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 66e0b68af147..8fa4d5f8eda1 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c | |||
@@ -232,7 +232,7 @@ static int get_parent_cell_index(struct device_node *np) | |||
232 | 232 | ||
233 | iprop = of_get_property(parent, "cell-index", NULL); | 233 | iprop = of_get_property(parent, "cell-index", NULL); |
234 | if (iprop) | 234 | if (iprop) |
235 | ret = *iprop; | 235 | ret = be32_to_cpup(iprop); |
236 | 236 | ||
237 | of_node_put(parent); | 237 | of_node_put(parent); |
238 | 238 | ||
@@ -261,7 +261,7 @@ static int codec_node_dev_name(struct device_node *np, char *buf, size_t len) | |||
261 | if (!iprop) | 261 | if (!iprop) |
262 | return -EINVAL; | 262 | return -EINVAL; |
263 | 263 | ||
264 | addr = *iprop; | 264 | addr = be32_to_cpup(iprop); |
265 | 265 | ||
266 | bus = get_parent_cell_index(np); | 266 | bus = get_parent_cell_index(np); |
267 | if (bus < 0) | 267 | if (bus < 0) |
@@ -308,7 +308,7 @@ static int get_dma_channel(struct device_node *ssi_np, | |||
308 | return -EINVAL; | 308 | return -EINVAL; |
309 | } | 309 | } |
310 | 310 | ||
311 | *dma_channel_id = *iprop; | 311 | *dma_channel_id = be32_to_cpup(iprop); |
312 | *dma_id = get_parent_cell_index(dma_channel_np); | 312 | *dma_id = get_parent_cell_index(dma_channel_np); |
313 | of_node_put(dma_channel_np); | 313 | of_node_put(dma_channel_np); |
314 | 314 | ||
@@ -379,7 +379,7 @@ static int p1022_ds_probe(struct platform_device *pdev) | |||
379 | ret = -EINVAL; | 379 | ret = -EINVAL; |
380 | goto error; | 380 | goto error; |
381 | } | 381 | } |
382 | mdata->ssi_id = *iprop; | 382 | mdata->ssi_id = be32_to_cpup(iprop); |
383 | 383 | ||
384 | /* Get the serial format and clock direction. */ | 384 | /* Get the serial format and clock direction. */ |
385 | sprop = of_get_property(np, "fsl,mode", NULL); | 385 | sprop = of_get_property(np, "fsl,mode", NULL); |
@@ -405,7 +405,7 @@ static int p1022_ds_probe(struct platform_device *pdev) | |||
405 | ret = -EINVAL; | 405 | ret = -EINVAL; |
406 | goto error; | 406 | goto error; |
407 | } | 407 | } |
408 | mdata->clk_frequency = *iprop; | 408 | mdata->clk_frequency = be32_to_cpup(iprop); |
409 | } else if (strcasecmp(sprop, "i2s-master") == 0) { | 409 | } else if (strcasecmp(sprop, "i2s-master") == 0) { |
410 | mdata->dai_format = SND_SOC_DAIFMT_I2S; | 410 | mdata->dai_format = SND_SOC_DAIFMT_I2S; |
411 | mdata->codec_clk_direction = SND_SOC_CLOCK_IN; | 411 | mdata->codec_clk_direction = SND_SOC_CLOCK_IN; |
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c index 413b78da248f..309c59e6fb6c 100644 --- a/sound/soc/imx/imx-pcm-fiq.c +++ b/sound/soc/imx/imx-pcm-fiq.c | |||
@@ -238,12 +238,14 @@ static struct snd_pcm_ops imx_pcm_ops = { | |||
238 | 238 | ||
239 | static int ssi_irq = 0; | 239 | static int ssi_irq = 0; |
240 | 240 | ||
241 | static int imx_pcm_fiq_new(struct snd_card *card, struct snd_soc_dai *dai, | 241 | static int imx_pcm_fiq_new(struct snd_soc_pcm_runtime *rtd) |
242 | struct snd_pcm *pcm) | ||
243 | { | 242 | { |
243 | struct snd_card *card = rtd->card->snd_card; | ||
244 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
245 | struct snd_pcm *pcm = rtd->pcm; | ||
244 | int ret; | 246 | int ret; |
245 | 247 | ||
246 | ret = imx_pcm_new(card, dai, pcm); | 248 | ret = imx_pcm_new(rtd); |
247 | if (ret) | 249 | if (ret) |
248 | return ret; | 250 | return ret; |
249 | 251 | ||
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 61fceb09cdb5..10a8e2783751 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c | |||
@@ -388,10 +388,11 @@ static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
388 | 388 | ||
389 | static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); | 389 | static u64 imx_pcm_dmamask = DMA_BIT_MASK(32); |
390 | 390 | ||
391 | int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 391 | int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) |
392 | struct snd_pcm *pcm) | ||
393 | { | 392 | { |
394 | 393 | struct snd_card *card = rtd->card->snd_card; | |
394 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
395 | struct snd_pcm *pcm = rtd->pcm; | ||
395 | int ret = 0; | 396 | int ret = 0; |
396 | 397 | ||
397 | if (!card->dev->dma_mask) | 398 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/imx/imx-ssi.h b/sound/soc/imx/imx-ssi.h index dc8a87530e3e..0a84cec3599e 100644 --- a/sound/soc/imx/imx-ssi.h +++ b/sound/soc/imx/imx-ssi.h | |||
@@ -225,8 +225,7 @@ struct snd_soc_platform *imx_ssi_dma_mx2_init(struct platform_device *pdev, | |||
225 | struct imx_ssi *ssi); | 225 | struct imx_ssi *ssi); |
226 | 226 | ||
227 | int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); | 227 | int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma); |
228 | int imx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 228 | int imx_pcm_new(struct snd_soc_pcm_runtime *rtd); |
229 | struct snd_pcm *pcm); | ||
230 | void imx_pcm_free(struct snd_pcm *pcm); | 229 | void imx_pcm_free(struct snd_pcm *pcm); |
231 | 230 | ||
232 | /* | 231 | /* |
diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c index fb1483f7c966..a7c9578be983 100644 --- a/sound/soc/jz4740/jz4740-pcm.c +++ b/sound/soc/jz4740/jz4740-pcm.c | |||
@@ -299,9 +299,11 @@ static void jz4740_pcm_free(struct snd_pcm *pcm) | |||
299 | 299 | ||
300 | static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); | 300 | static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); |
301 | 301 | ||
302 | int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 302 | int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd) |
303 | struct snd_pcm *pcm) | ||
304 | { | 303 | { |
304 | struct snd_card *card = rtd->card->snd_card; | ||
305 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
306 | struct snd_pcm *pcm = rtd->pcm; | ||
305 | int ret = 0; | 307 | int ret = 0; |
306 | 308 | ||
307 | if (!card->dev->dma_mask) | 309 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index e13c6ce46328..cd33de1c5b7a 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c | |||
@@ -312,9 +312,11 @@ static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm, | |||
312 | return 0; | 312 | return 0; |
313 | } | 313 | } |
314 | 314 | ||
315 | static int kirkwood_dma_new(struct snd_card *card, | 315 | static int kirkwood_dma_new(struct snd_soc_pcm_runtime *rtd) |
316 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
317 | { | 316 | { |
317 | struct snd_card *card = rtd->card->snd_card; | ||
318 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
319 | struct snd_pcm *pcm = rtd->pcm; | ||
318 | int ret; | 320 | int ret; |
319 | 321 | ||
320 | if (!card->dev->dma_mask) | 322 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c index 5a946b4115a2..3e7826058efe 100644 --- a/sound/soc/mid-x86/sst_platform.c +++ b/sound/soc/mid-x86/sst_platform.c | |||
@@ -402,9 +402,10 @@ static void sst_pcm_free(struct snd_pcm *pcm) | |||
402 | snd_pcm_lib_preallocate_free_for_all(pcm); | 402 | snd_pcm_lib_preallocate_free_for_all(pcm); |
403 | } | 403 | } |
404 | 404 | ||
405 | int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 405 | int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) |
406 | struct snd_pcm *pcm) | ||
407 | { | 406 | { |
407 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
408 | struct snd_pcm *pcm = rtd->pcm; | ||
408 | int retval = 0; | 409 | int retval = 0; |
409 | 410 | ||
410 | pr_debug("sst_pcm_new called\n"); | 411 | pr_debug("sst_pcm_new called\n"); |
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index dac6732da969..9c0edad90d8b 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c | |||
@@ -356,7 +356,7 @@ static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev) | |||
356 | nuc900_audio->irq_num = platform_get_irq(pdev, 0); | 356 | nuc900_audio->irq_num = platform_get_irq(pdev, 0); |
357 | if (!nuc900_audio->irq_num) { | 357 | if (!nuc900_audio->irq_num) { |
358 | ret = -EBUSY; | 358 | ret = -EBUSY; |
359 | goto out2; | 359 | goto out3; |
360 | } | 360 | } |
361 | 361 | ||
362 | nuc900_ac97_data = nuc900_audio; | 362 | nuc900_ac97_data = nuc900_audio; |
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 8263f56dc665..d589ef14e917 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c | |||
@@ -315,9 +315,12 @@ static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm) | |||
315 | } | 315 | } |
316 | 316 | ||
317 | static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); | 317 | static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32); |
318 | static int nuc900_dma_new(struct snd_card *card, | 318 | static int nuc900_dma_new(struct snd_soc_pcm_runtime *rtd) |
319 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
320 | { | 319 | { |
320 | struct snd_card *card = rtd->card->snd_card; | ||
321 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
322 | struct snd_pcm *pcm = rtd->pcm; | ||
323 | |||
321 | if (!card->dev->dma_mask) | 324 | if (!card->dev->dma_mask) |
322 | card->dev->dma_mask = &nuc900_pcm_dmamask; | 325 | card->dev->dma_mask = &nuc900_pcm_dmamask; |
323 | if (!card->dev->coherent_dma_mask) | 326 | if (!card->dev->coherent_dma_mask) |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 99054cf1f68f..fe83d0d176be 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -9,6 +9,9 @@ config SND_OMAP_SOC_MCBSP | |||
9 | config SND_OMAP_SOC_MCPDM | 9 | config SND_OMAP_SOC_MCPDM |
10 | tristate | 10 | tristate |
11 | 11 | ||
12 | config SND_OMAP_SOC_HDMI | ||
13 | tristate | ||
14 | |||
12 | config SND_OMAP_SOC_N810 | 15 | config SND_OMAP_SOC_N810 |
13 | tristate "SoC Audio support for Nokia N810" | 16 | tristate "SoC Audio support for Nokia N810" |
14 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C | 17 | depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C |
@@ -100,6 +103,14 @@ config SND_OMAP_SOC_SDP4430 | |||
100 | Say Y if you want to add support for SoC audio on Texas Instruments | 103 | Say Y if you want to add support for SoC audio on Texas Instruments |
101 | SDP4430. | 104 | SDP4430. |
102 | 105 | ||
106 | config SND_OMAP_SOC_OMAP4_HDMI | ||
107 | tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" | ||
108 | depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 | ||
109 | select SND_OMAP_SOC_HDMI | ||
110 | help | ||
111 | Say Y if you want to add support for SoC HDMI audio on Texas Instruments | ||
112 | OMAP4 chips | ||
113 | |||
103 | config SND_OMAP_SOC_OMAP3_PANDORA | 114 | config SND_OMAP_SOC_OMAP3_PANDORA |
104 | tristate "SoC Audio support for OMAP3 Pandora" | 115 | tristate "SoC Audio support for OMAP3 Pandora" |
105 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA | 116 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA |
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index 6c2c87eed5bb..59e2c8d1e38d 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
@@ -2,10 +2,12 @@ | |||
2 | snd-soc-omap-objs := omap-pcm.o | 2 | snd-soc-omap-objs := omap-pcm.o |
3 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o | 3 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o |
4 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o | 4 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o mcpdm.o |
5 | snd-soc-omap-hdmi-objs := omap-hdmi.o | ||
5 | 6 | ||
6 | obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o | 7 | obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o |
7 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o | 8 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o |
8 | obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o | 9 | obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o |
10 | obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o | ||
9 | 11 | ||
10 | # OMAP Machine Support | 12 | # OMAP Machine Support |
11 | snd-soc-n810-objs := n810.o | 13 | snd-soc-n810-objs := n810.o |
@@ -21,6 +23,7 @@ snd-soc-omap3pandora-objs := omap3pandora.o | |||
21 | snd-soc-omap3beagle-objs := omap3beagle.o | 23 | snd-soc-omap3beagle-objs := omap3beagle.o |
22 | snd-soc-zoom2-objs := zoom2.o | 24 | snd-soc-zoom2-objs := zoom2.o |
23 | snd-soc-igep0020-objs := igep0020.o | 25 | snd-soc-igep0020-objs := igep0020.o |
26 | snd-soc-omap4-hdmi-objs := omap4-hdmi-card.o | ||
24 | 27 | ||
25 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 28 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
26 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o | 29 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o |
@@ -36,3 +39,4 @@ obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | |||
36 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o | 39 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_BEAGLE) += snd-soc-omap3beagle.o |
37 | obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o | 40 | obj-$(CONFIG_SND_OMAP_SOC_ZOOM2) += snd-soc-zoom2.o |
38 | obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o | 41 | obj-$(CONFIG_SND_OMAP_SOC_IGEP0020) += snd-soc-igep0020.o |
42 | obj-$(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) += snd-soc-omap4-hdmi.o | ||
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 462cbcbea74a..b40095a19883 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c | |||
@@ -427,7 +427,8 @@ static struct snd_soc_ops ams_delta_ops = { | |||
427 | 427 | ||
428 | /* Board specific codec bias level control */ | 428 | /* Board specific codec bias level control */ |
429 | static int ams_delta_set_bias_level(struct snd_soc_card *card, | 429 | static int ams_delta_set_bias_level(struct snd_soc_card *card, |
430 | enum snd_soc_bias_level level) | 430 | struct snd_soc_dapm_context *dapm, |
431 | enum snd_soc_bias_level level) | ||
431 | { | 432 | { |
432 | struct snd_soc_codec *codec = card->rtd->codec; | 433 | struct snd_soc_codec *codec = card->rtd->codec; |
433 | 434 | ||
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c new file mode 100644 index 000000000000..36c6eaeffb02 --- /dev/null +++ b/sound/soc/omap/omap-hdmi.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * omap-hdmi.c | ||
3 | * | ||
4 | * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. | ||
5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * Authors: Jorge Candelaria <jorge.candelaria@ti.com> | ||
7 | * Ricardo Neri <ricardo.neri@ti.com> | ||
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 | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/initval.h> | ||
32 | #include <sound/soc.h> | ||
33 | |||
34 | #include <plat/dma.h> | ||
35 | #include "omap-pcm.h" | ||
36 | #include "omap-hdmi.h" | ||
37 | |||
38 | #define DRV_NAME "hdmi-audio-dai" | ||
39 | |||
40 | static struct omap_pcm_dma_data omap_hdmi_dai_dma_params = { | ||
41 | .name = "HDMI playback", | ||
42 | .sync_mode = OMAP_DMA_SYNC_PACKET, | ||
43 | }; | ||
44 | |||
45 | static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, | ||
46 | struct snd_soc_dai *dai) | ||
47 | { | ||
48 | int err; | ||
49 | /* | ||
50 | * Make sure that the period bytes are multiple of the DMA packet size. | ||
51 | * Largest packet size we use is 32 32-bit words = 128 bytes | ||
52 | */ | ||
53 | err = snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
54 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); | ||
55 | if (err < 0) | ||
56 | return err; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, | ||
62 | struct snd_pcm_hw_params *params, | ||
63 | struct snd_soc_dai *dai) | ||
64 | { | ||
65 | int err = 0; | ||
66 | |||
67 | switch (params_format(params)) { | ||
68 | case SNDRV_PCM_FORMAT_S16_LE: | ||
69 | omap_hdmi_dai_dma_params.packet_size = 16; | ||
70 | break; | ||
71 | case SNDRV_PCM_FORMAT_S24_LE: | ||
72 | omap_hdmi_dai_dma_params.packet_size = 32; | ||
73 | break; | ||
74 | default: | ||
75 | err = -EINVAL; | ||
76 | } | ||
77 | |||
78 | omap_hdmi_dai_dma_params.data_type = OMAP_DMA_DATA_TYPE_S32; | ||
79 | |||
80 | snd_soc_dai_set_dma_data(dai, substream, | ||
81 | &omap_hdmi_dai_dma_params); | ||
82 | |||
83 | return err; | ||
84 | } | ||
85 | |||
86 | static struct snd_soc_dai_ops omap_hdmi_dai_ops = { | ||
87 | .startup = omap_hdmi_dai_startup, | ||
88 | .hw_params = omap_hdmi_dai_hw_params, | ||
89 | }; | ||
90 | |||
91 | static struct snd_soc_dai_driver omap_hdmi_dai = { | ||
92 | .playback = { | ||
93 | .channels_min = 2, | ||
94 | .channels_max = 2, | ||
95 | .rates = OMAP_HDMI_RATES, | ||
96 | .formats = OMAP_HDMI_FORMATS, | ||
97 | }, | ||
98 | .ops = &omap_hdmi_dai_ops, | ||
99 | }; | ||
100 | |||
101 | static __devinit int omap_hdmi_probe(struct platform_device *pdev) | ||
102 | { | ||
103 | int ret; | ||
104 | struct resource *hdmi_rsrc; | ||
105 | |||
106 | hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
107 | if (!hdmi_rsrc) { | ||
108 | dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); | ||
109 | return -EINVAL; | ||
110 | } | ||
111 | |||
112 | omap_hdmi_dai_dma_params.port_addr = hdmi_rsrc->start | ||
113 | + OMAP_HDMI_AUDIO_DMA_PORT; | ||
114 | |||
115 | hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
116 | if (!hdmi_rsrc) { | ||
117 | dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n"); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | |||
121 | omap_hdmi_dai_dma_params.dma_req = hdmi_rsrc->start; | ||
122 | |||
123 | ret = snd_soc_register_dai(&pdev->dev, &omap_hdmi_dai); | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static int __devexit omap_hdmi_remove(struct platform_device *pdev) | ||
128 | { | ||
129 | snd_soc_unregister_dai(&pdev->dev); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static struct platform_driver hdmi_dai_driver = { | ||
134 | .driver = { | ||
135 | .name = DRV_NAME, | ||
136 | .owner = THIS_MODULE, | ||
137 | }, | ||
138 | .probe = omap_hdmi_probe, | ||
139 | .remove = __devexit_p(omap_hdmi_remove), | ||
140 | }; | ||
141 | |||
142 | static int __init hdmi_dai_init(void) | ||
143 | { | ||
144 | return platform_driver_register(&hdmi_dai_driver); | ||
145 | } | ||
146 | module_init(hdmi_dai_init); | ||
147 | |||
148 | static void __exit hdmi_dai_exit(void) | ||
149 | { | ||
150 | platform_driver_unregister(&hdmi_dai_driver); | ||
151 | } | ||
152 | module_exit(hdmi_dai_exit); | ||
153 | |||
154 | MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>"); | ||
155 | MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); | ||
156 | MODULE_DESCRIPTION("OMAP HDMI SoC Interface"); | ||
157 | MODULE_LICENSE("GPL"); | ||
158 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h new file mode 100644 index 000000000000..34c298d5057e --- /dev/null +++ b/sound/soc/omap/omap-hdmi.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * omap-hdmi.h | ||
3 | * | ||
4 | * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. | ||
5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * Authors: Jorge Candelaria <jorge.candelaria@ti.com> | ||
7 | * Ricardo Neri <ricardo.neri@ti.com> | ||
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 | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __OMAP_HDMI_H__ | ||
26 | #define __OMAP_HDMI_H__ | ||
27 | |||
28 | #define OMAP_HDMI_AUDIO_DMA_PORT 0x8c | ||
29 | |||
30 | #define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ | ||
31 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
32 | |||
33 | #define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
34 | SNDRV_PCM_FMTBIT_S24_LE) | ||
35 | |||
36 | #endif | ||
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index e6a6b991d05f..b2f5751edae3 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -366,9 +366,11 @@ static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
366 | } | 366 | } |
367 | } | 367 | } |
368 | 368 | ||
369 | static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 369 | static int omap_pcm_new(struct snd_soc_pcm_runtime *rtd) |
370 | struct snd_pcm *pcm) | ||
371 | { | 370 | { |
371 | struct snd_card *card = rtd->card->snd_card; | ||
372 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
373 | struct snd_pcm *pcm = rtd->pcm; | ||
372 | int ret = 0; | 374 | int ret = 0; |
373 | 375 | ||
374 | if (!card->dev->dma_mask) | 376 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/omap/omap4-hdmi-card.c b/sound/soc/omap/omap4-hdmi-card.c new file mode 100644 index 000000000000..9f32615b81f7 --- /dev/null +++ b/sound/soc/omap/omap4-hdmi-card.c | |||
@@ -0,0 +1,129 @@ | |||
1 | /* | ||
2 | * omap4-hdmi-card.c | ||
3 | * | ||
4 | * OMAP ALSA SoC machine driver for TI OMAP4 HDMI | ||
5 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * Author: Ricardo Neri <ricardo.neri@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 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
20 | * 02110-1301 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <asm/mach-types.h> | ||
27 | #include <video/omapdss.h> | ||
28 | |||
29 | #define DRV_NAME "omap4-hdmi-audio" | ||
30 | |||
31 | static int omap4_hdmi_dai_hw_params(struct snd_pcm_substream *substream, | ||
32 | struct snd_pcm_hw_params *params) | ||
33 | { | ||
34 | int i; | ||
35 | struct omap_overlay_manager *mgr = NULL; | ||
36 | struct device *dev = substream->pcm->card->dev; | ||
37 | |||
38 | /* Find DSS HDMI device */ | ||
39 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { | ||
40 | mgr = omap_dss_get_overlay_manager(i); | ||
41 | if (mgr && mgr->device | ||
42 | && mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) | ||
43 | break; | ||
44 | } | ||
45 | |||
46 | if (i == omap_dss_get_num_overlay_managers()) { | ||
47 | dev_err(dev, "HDMI display device not found!\n"); | ||
48 | return -ENODEV; | ||
49 | } | ||
50 | |||
51 | /* Make sure HDMI is power-on to avoid L3 interconnect errors */ | ||
52 | if (mgr->device->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
53 | dev_err(dev, "HDMI display is not active!\n"); | ||
54 | return -EIO; | ||
55 | } | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static struct snd_soc_ops omap4_hdmi_dai_ops = { | ||
61 | .hw_params = omap4_hdmi_dai_hw_params, | ||
62 | }; | ||
63 | |||
64 | static struct snd_soc_dai_link omap4_hdmi_dai = { | ||
65 | .name = "HDMI", | ||
66 | .stream_name = "HDMI", | ||
67 | .cpu_dai_name = "hdmi-audio-dai", | ||
68 | .platform_name = "omap-pcm-audio", | ||
69 | .codec_name = "omapdss_hdmi", | ||
70 | .codec_dai_name = "hdmi-audio-codec", | ||
71 | .ops = &omap4_hdmi_dai_ops, | ||
72 | }; | ||
73 | |||
74 | static struct snd_soc_card snd_soc_omap4_hdmi = { | ||
75 | .name = "OMAP4HDMI", | ||
76 | .dai_link = &omap4_hdmi_dai, | ||
77 | .num_links = 1, | ||
78 | }; | ||
79 | |||
80 | static __devinit int omap4_hdmi_probe(struct platform_device *pdev) | ||
81 | { | ||
82 | struct snd_soc_card *card = &snd_soc_omap4_hdmi; | ||
83 | int ret; | ||
84 | |||
85 | card->dev = &pdev->dev; | ||
86 | |||
87 | ret = snd_soc_register_card(card); | ||
88 | if (ret) { | ||
89 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | ||
90 | card->dev = NULL; | ||
91 | return ret; | ||
92 | } | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int __devexit omap4_hdmi_remove(struct platform_device *pdev) | ||
97 | { | ||
98 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
99 | |||
100 | snd_soc_unregister_card(card); | ||
101 | card->dev = NULL; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static struct platform_driver omap4_hdmi_driver = { | ||
106 | .driver = { | ||
107 | .name = "omap4-hdmi-audio", | ||
108 | .owner = THIS_MODULE, | ||
109 | }, | ||
110 | .probe = omap4_hdmi_probe, | ||
111 | .remove = __devexit_p(omap4_hdmi_remove), | ||
112 | }; | ||
113 | |||
114 | static int __init omap4_hdmi_init(void) | ||
115 | { | ||
116 | return platform_driver_register(&omap4_hdmi_driver); | ||
117 | } | ||
118 | module_init(omap4_hdmi_init); | ||
119 | |||
120 | static void __exit omap4_hdmi_exit(void) | ||
121 | { | ||
122 | platform_driver_unregister(&omap4_hdmi_driver); | ||
123 | } | ||
124 | module_exit(omap4_hdmi_exit); | ||
125 | |||
126 | MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); | ||
127 | MODULE_DESCRIPTION("OMAP4 HDMI machine ASoC driver"); | ||
128 | MODULE_LICENSE("GPL"); | ||
129 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index fab20a54e863..c43060053dd7 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -85,9 +85,10 @@ static struct snd_pcm_ops pxa2xx_pcm_ops = { | |||
85 | 85 | ||
86 | static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32); | 86 | static u64 pxa2xx_pcm_dmamask = DMA_BIT_MASK(32); |
87 | 87 | ||
88 | static int pxa2xx_soc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 88 | static int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd) |
89 | struct snd_pcm *pcm) | ||
90 | { | 89 | { |
90 | struct snd_card *card = rtd->card->snd_card; | ||
91 | struct snd_pcm *pcm = rtd->pcm; | ||
91 | int ret = 0; | 92 | int ret = 0; |
92 | 93 | ||
93 | if (!card->dev->dma_mask) | 94 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index ab3ccaec72d2..80c85fd64e1a 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c | |||
@@ -443,10 +443,11 @@ static void s6000_pcm_free(struct snd_pcm *pcm) | |||
443 | 443 | ||
444 | static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32); | 444 | static u64 s6000_pcm_dmamask = DMA_BIT_MASK(32); |
445 | 445 | ||
446 | static int s6000_pcm_new(struct snd_card *card, | 446 | static int s6000_pcm_new(struct snd_soc_pcm_runtime *runtime) |
447 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
448 | { | 447 | { |
449 | struct snd_soc_pcm_runtime *runtime = pcm->private_data; | 448 | struct snd_card *card = runtime->card->snd_card; |
449 | struct snd_soc_dai *dai = runtime->cpu_dai; | ||
450 | struct snd_pcm *pcm = runtime->pcm; | ||
450 | struct s6000_pcm_dma_params *params; | 451 | struct s6000_pcm_dma_params *params; |
451 | int res; | 452 | int res; |
452 | 453 | ||
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index d155cbb58e1c..54b0e4b7faf7 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -158,7 +158,7 @@ config SND_SOC_GONI_AQUILA_WM8994 | |||
158 | 158 | ||
159 | config SND_SOC_SAMSUNG_SMDK_SPDIF | 159 | config SND_SOC_SAMSUNG_SMDK_SPDIF |
160 | tristate "SoC S/PDIF Audio support for SMDK" | 160 | tristate "SoC S/PDIF Audio support for SMDK" |
161 | depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210) | 161 | depends on SND_SOC_SAMSUNG && (MACH_SMDKC100 || MACH_SMDKC110 || MACH_SMDKV210 || MACH_SMDKV310) |
162 | select SND_SAMSUNG_SPDIF | 162 | select SND_SAMSUNG_SPDIF |
163 | help | 163 | help |
164 | Say Y if you want to add support for SoC S/PDIF audio on the SMDK. | 164 | Say Y if you want to add support for SoC S/PDIF audio on the SMDK. |
@@ -171,9 +171,23 @@ config SND_SOC_SMDK_WM8580_PCM | |||
171 | help | 171 | help |
172 | Say Y if you want to add support for SoC audio on the SMDK. | 172 | Say Y if you want to add support for SoC audio on the SMDK. |
173 | 173 | ||
174 | config SND_SOC_SMDK_WM8994_PCM | ||
175 | tristate "SoC PCM Audio support for WM8994 on SMDK" | ||
176 | depends on SND_SOC_SAMSUNG && (MACH_SMDKC210 || MACH_SMDKV310) | ||
177 | select SND_SOC_WM8994 | ||
178 | select SND_SAMSUNG_PCM | ||
179 | help | ||
180 | Say Y if you want to add support for SoC audio on the SMDK | ||
181 | |||
174 | config SND_SOC_SPEYSIDE | 182 | config SND_SOC_SPEYSIDE |
175 | tristate "Audio support for Wolfson Speyside" | 183 | tristate "Audio support for Wolfson Speyside" |
176 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 | 184 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 |
177 | select SND_SAMSUNG_I2S | 185 | select SND_SAMSUNG_I2S |
178 | select SND_SOC_WM8915 | 186 | select SND_SOC_WM8915 |
179 | select SND_SOC_WM9081 | 187 | select SND_SOC_WM9081 |
188 | |||
189 | config SND_SOC_SPEYSIDE_WM8962 | ||
190 | tristate "Audio support for Wolfson Speyside with WM8962" | ||
191 | depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 | ||
192 | select SND_SAMSUNG_I2S | ||
193 | select SND_SOC_WM8962 | ||
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 683843a2744f..9eb3b12eb72f 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile | |||
@@ -35,7 +35,9 @@ snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o | |||
35 | snd-soc-goni-wm8994-objs := goni_wm8994.o | 35 | snd-soc-goni-wm8994-objs := goni_wm8994.o |
36 | snd-soc-smdk-spdif-objs := smdk_spdif.o | 36 | snd-soc-smdk-spdif-objs := smdk_spdif.o |
37 | snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o | 37 | snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o |
38 | snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o | ||
38 | snd-soc-speyside-objs := speyside.o | 39 | snd-soc-speyside-objs := speyside.o |
40 | snd-soc-speyside-wm8962-objs := speyside_wm8962.o | ||
39 | 41 | ||
40 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o | 42 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o |
41 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 43 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -54,4 +56,6 @@ obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o | |||
54 | obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o | 56 | obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o |
55 | obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o | 57 | obj-$(CONFIG_SND_SOC_GONI_AQUILA_WM8994) += snd-soc-goni-wm8994.o |
56 | obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o | 58 | obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o |
59 | obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o | ||
57 | obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o | 60 | obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o |
61 | obj-$(CONFIG_SND_SOC_SPEYSIDE_WM8962) += snd-soc-speyside-wm8962.o | ||
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 5cb3b880f0d5..9465588b02f2 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c | |||
@@ -425,9 +425,11 @@ static void dma_free_dma_buffers(struct snd_pcm *pcm) | |||
425 | 425 | ||
426 | static u64 dma_mask = DMA_BIT_MASK(32); | 426 | static u64 dma_mask = DMA_BIT_MASK(32); |
427 | 427 | ||
428 | static int dma_new(struct snd_card *card, | 428 | static int dma_new(struct snd_soc_pcm_runtime *rtd) |
429 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
430 | { | 429 | { |
430 | struct snd_card *card = rtd->card->snd_card; | ||
431 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
432 | struct snd_pcm *pcm = rtd->pcm; | ||
431 | int ret = 0; | 433 | int ret = 0; |
432 | 434 | ||
433 | pr_debug("Entered %s\n", __func__); | 435 | pr_debug("Entered %s\n", __func__); |
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h new file mode 100644 index 000000000000..c0e6d9a19efc --- /dev/null +++ b/sound/soc/samsung/i2s-regs.h | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/samsung/i2s-regs.h | ||
3 | * | ||
4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com | ||
6 | * | ||
7 | * Samsung I2S driver's register header | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | #ifndef __SND_SOC_SAMSUNG_I2S_REGS_H | ||
16 | #define __SND_SOC_SAMSUNG_I2S_REGS_H | ||
17 | |||
18 | #define I2SCON 0x0 | ||
19 | #define I2SMOD 0x4 | ||
20 | #define I2SFIC 0x8 | ||
21 | #define I2SPSR 0xc | ||
22 | #define I2STXD 0x10 | ||
23 | #define I2SRXD 0x14 | ||
24 | #define I2SFICS 0x18 | ||
25 | #define I2STXDS 0x1c | ||
26 | #define I2SAHB 0x20 | ||
27 | #define I2SSTR0 0x24 | ||
28 | #define I2SSIZE 0x28 | ||
29 | #define I2STRNCNT 0x2c | ||
30 | #define I2SLVL0ADDR 0x30 | ||
31 | #define I2SLVL1ADDR 0x34 | ||
32 | #define I2SLVL2ADDR 0x38 | ||
33 | #define I2SLVL3ADDR 0x3c | ||
34 | |||
35 | #define CON_RSTCLR (1 << 31) | ||
36 | #define CON_FRXOFSTATUS (1 << 26) | ||
37 | #define CON_FRXORINTEN (1 << 25) | ||
38 | #define CON_FTXSURSTAT (1 << 24) | ||
39 | #define CON_FTXSURINTEN (1 << 23) | ||
40 | #define CON_TXSDMA_PAUSE (1 << 20) | ||
41 | #define CON_TXSDMA_ACTIVE (1 << 18) | ||
42 | |||
43 | #define CON_FTXURSTATUS (1 << 17) | ||
44 | #define CON_FTXURINTEN (1 << 16) | ||
45 | #define CON_TXFIFO2_EMPTY (1 << 15) | ||
46 | #define CON_TXFIFO1_EMPTY (1 << 14) | ||
47 | #define CON_TXFIFO2_FULL (1 << 13) | ||
48 | #define CON_TXFIFO1_FULL (1 << 12) | ||
49 | |||
50 | #define CON_LRINDEX (1 << 11) | ||
51 | #define CON_TXFIFO_EMPTY (1 << 10) | ||
52 | #define CON_RXFIFO_EMPTY (1 << 9) | ||
53 | #define CON_TXFIFO_FULL (1 << 8) | ||
54 | #define CON_RXFIFO_FULL (1 << 7) | ||
55 | #define CON_TXDMA_PAUSE (1 << 6) | ||
56 | #define CON_RXDMA_PAUSE (1 << 5) | ||
57 | #define CON_TXCH_PAUSE (1 << 4) | ||
58 | #define CON_RXCH_PAUSE (1 << 3) | ||
59 | #define CON_TXDMA_ACTIVE (1 << 2) | ||
60 | #define CON_RXDMA_ACTIVE (1 << 1) | ||
61 | #define CON_ACTIVE (1 << 0) | ||
62 | |||
63 | #define MOD_OPCLK_CDCLK_OUT (0 << 30) | ||
64 | #define MOD_OPCLK_CDCLK_IN (1 << 30) | ||
65 | #define MOD_OPCLK_BCLK_OUT (2 << 30) | ||
66 | #define MOD_OPCLK_PCLK (3 << 30) | ||
67 | #define MOD_OPCLK_MASK (3 << 30) | ||
68 | #define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */ | ||
69 | |||
70 | #define MOD_BLCS_SHIFT 26 | ||
71 | #define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT) | ||
72 | #define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT) | ||
73 | #define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT) | ||
74 | #define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT) | ||
75 | #define MOD_BLCP_SHIFT 24 | ||
76 | #define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT) | ||
77 | #define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT) | ||
78 | #define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT) | ||
79 | #define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT) | ||
80 | |||
81 | #define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */ | ||
82 | #define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */ | ||
83 | #define MOD_C1DD_HHALF (1 << 19) | ||
84 | #define MOD_C1DD_LHALF (1 << 18) | ||
85 | #define MOD_DC2_EN (1 << 17) | ||
86 | #define MOD_DC1_EN (1 << 16) | ||
87 | #define MOD_BLC_16BIT (0 << 13) | ||
88 | #define MOD_BLC_8BIT (1 << 13) | ||
89 | #define MOD_BLC_24BIT (2 << 13) | ||
90 | #define MOD_BLC_MASK (3 << 13) | ||
91 | |||
92 | #define MOD_IMS_SYSMUX (1 << 10) | ||
93 | #define MOD_SLAVE (1 << 11) | ||
94 | #define MOD_TXONLY (0 << 8) | ||
95 | #define MOD_RXONLY (1 << 8) | ||
96 | #define MOD_TXRX (2 << 8) | ||
97 | #define MOD_MASK (3 << 8) | ||
98 | #define MOD_LR_LLOW (0 << 7) | ||
99 | #define MOD_LR_RLOW (1 << 7) | ||
100 | #define MOD_SDF_IIS (0 << 5) | ||
101 | #define MOD_SDF_MSB (1 << 5) | ||
102 | #define MOD_SDF_LSB (2 << 5) | ||
103 | #define MOD_SDF_MASK (3 << 5) | ||
104 | #define MOD_RCLK_256FS (0 << 3) | ||
105 | #define MOD_RCLK_512FS (1 << 3) | ||
106 | #define MOD_RCLK_384FS (2 << 3) | ||
107 | #define MOD_RCLK_768FS (3 << 3) | ||
108 | #define MOD_RCLK_MASK (3 << 3) | ||
109 | #define MOD_BCLK_32FS (0 << 1) | ||
110 | #define MOD_BCLK_48FS (1 << 1) | ||
111 | #define MOD_BCLK_16FS (2 << 1) | ||
112 | #define MOD_BCLK_24FS (3 << 1) | ||
113 | #define MOD_BCLK_MASK (3 << 1) | ||
114 | #define MOD_8BIT (1 << 0) | ||
115 | |||
116 | #define MOD_CDCLKCON (1 << 12) | ||
117 | |||
118 | #define PSR_PSREN (1 << 15) | ||
119 | |||
120 | #define FIC_TX2COUNT(x) (((x) >> 24) & 0xf) | ||
121 | #define FIC_TX1COUNT(x) (((x) >> 16) & 0xf) | ||
122 | |||
123 | #define FIC_TXFLUSH (1 << 15) | ||
124 | #define FIC_RXFLUSH (1 << 7) | ||
125 | |||
126 | #define FIC_TXCOUNT(x) (((x) >> 8) & 0xf) | ||
127 | #define FIC_RXCOUNT(x) (((x) >> 0) & 0xf) | ||
128 | #define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f) | ||
129 | |||
130 | #define AHB_INTENLVL0 (1 << 24) | ||
131 | #define AHB_LVL0INT (1 << 20) | ||
132 | #define AHB_CLRLVL0INT (1 << 16) | ||
133 | #define AHB_DMARLD (1 << 5) | ||
134 | #define AHB_INTMASK (1 << 3) | ||
135 | #define AHB_DMAEN (1 << 0) | ||
136 | #define AHB_LVLINTMASK (0xf << 20) | ||
137 | |||
138 | #define I2SSIZE_TRNMSK (0xffff) | ||
139 | #define I2SSIZE_SHIFT (16) | ||
140 | |||
141 | #endif /* __SND_SOC_SAMSUNG_I2S_REGS_H */ | ||
142 | |||
143 | |||
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 992a732b5211..1568eea31f41 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -22,109 +22,7 @@ | |||
22 | 22 | ||
23 | #include "dma.h" | 23 | #include "dma.h" |
24 | #include "i2s.h" | 24 | #include "i2s.h" |
25 | 25 | #include "i2s-regs.h" | |
26 | #define I2SCON 0x0 | ||
27 | #define I2SMOD 0x4 | ||
28 | #define I2SFIC 0x8 | ||
29 | #define I2SPSR 0xc | ||
30 | #define I2STXD 0x10 | ||
31 | #define I2SRXD 0x14 | ||
32 | #define I2SFICS 0x18 | ||
33 | #define I2STXDS 0x1c | ||
34 | |||
35 | #define CON_RSTCLR (1 << 31) | ||
36 | #define CON_FRXOFSTATUS (1 << 26) | ||
37 | #define CON_FRXORINTEN (1 << 25) | ||
38 | #define CON_FTXSURSTAT (1 << 24) | ||
39 | #define CON_FTXSURINTEN (1 << 23) | ||
40 | #define CON_TXSDMA_PAUSE (1 << 20) | ||
41 | #define CON_TXSDMA_ACTIVE (1 << 18) | ||
42 | |||
43 | #define CON_FTXURSTATUS (1 << 17) | ||
44 | #define CON_FTXURINTEN (1 << 16) | ||
45 | #define CON_TXFIFO2_EMPTY (1 << 15) | ||
46 | #define CON_TXFIFO1_EMPTY (1 << 14) | ||
47 | #define CON_TXFIFO2_FULL (1 << 13) | ||
48 | #define CON_TXFIFO1_FULL (1 << 12) | ||
49 | |||
50 | #define CON_LRINDEX (1 << 11) | ||
51 | #define CON_TXFIFO_EMPTY (1 << 10) | ||
52 | #define CON_RXFIFO_EMPTY (1 << 9) | ||
53 | #define CON_TXFIFO_FULL (1 << 8) | ||
54 | #define CON_RXFIFO_FULL (1 << 7) | ||
55 | #define CON_TXDMA_PAUSE (1 << 6) | ||
56 | #define CON_RXDMA_PAUSE (1 << 5) | ||
57 | #define CON_TXCH_PAUSE (1 << 4) | ||
58 | #define CON_RXCH_PAUSE (1 << 3) | ||
59 | #define CON_TXDMA_ACTIVE (1 << 2) | ||
60 | #define CON_RXDMA_ACTIVE (1 << 1) | ||
61 | #define CON_ACTIVE (1 << 0) | ||
62 | |||
63 | #define MOD_OPCLK_CDCLK_OUT (0 << 30) | ||
64 | #define MOD_OPCLK_CDCLK_IN (1 << 30) | ||
65 | #define MOD_OPCLK_BCLK_OUT (2 << 30) | ||
66 | #define MOD_OPCLK_PCLK (3 << 30) | ||
67 | #define MOD_OPCLK_MASK (3 << 30) | ||
68 | #define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */ | ||
69 | |||
70 | #define MOD_BLCS_SHIFT 26 | ||
71 | #define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT) | ||
72 | #define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT) | ||
73 | #define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT) | ||
74 | #define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT) | ||
75 | #define MOD_BLCP_SHIFT 24 | ||
76 | #define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT) | ||
77 | #define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT) | ||
78 | #define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT) | ||
79 | #define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT) | ||
80 | |||
81 | #define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */ | ||
82 | #define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */ | ||
83 | #define MOD_C1DD_HHALF (1 << 19) | ||
84 | #define MOD_C1DD_LHALF (1 << 18) | ||
85 | #define MOD_DC2_EN (1 << 17) | ||
86 | #define MOD_DC1_EN (1 << 16) | ||
87 | #define MOD_BLC_16BIT (0 << 13) | ||
88 | #define MOD_BLC_8BIT (1 << 13) | ||
89 | #define MOD_BLC_24BIT (2 << 13) | ||
90 | #define MOD_BLC_MASK (3 << 13) | ||
91 | |||
92 | #define MOD_IMS_SYSMUX (1 << 10) | ||
93 | #define MOD_SLAVE (1 << 11) | ||
94 | #define MOD_TXONLY (0 << 8) | ||
95 | #define MOD_RXONLY (1 << 8) | ||
96 | #define MOD_TXRX (2 << 8) | ||
97 | #define MOD_MASK (3 << 8) | ||
98 | #define MOD_LR_LLOW (0 << 7) | ||
99 | #define MOD_LR_RLOW (1 << 7) | ||
100 | #define MOD_SDF_IIS (0 << 5) | ||
101 | #define MOD_SDF_MSB (1 << 5) | ||
102 | #define MOD_SDF_LSB (2 << 5) | ||
103 | #define MOD_SDF_MASK (3 << 5) | ||
104 | #define MOD_RCLK_256FS (0 << 3) | ||
105 | #define MOD_RCLK_512FS (1 << 3) | ||
106 | #define MOD_RCLK_384FS (2 << 3) | ||
107 | #define MOD_RCLK_768FS (3 << 3) | ||
108 | #define MOD_RCLK_MASK (3 << 3) | ||
109 | #define MOD_BCLK_32FS (0 << 1) | ||
110 | #define MOD_BCLK_48FS (1 << 1) | ||
111 | #define MOD_BCLK_16FS (2 << 1) | ||
112 | #define MOD_BCLK_24FS (3 << 1) | ||
113 | #define MOD_BCLK_MASK (3 << 1) | ||
114 | #define MOD_8BIT (1 << 0) | ||
115 | |||
116 | #define MOD_CDCLKCON (1 << 12) | ||
117 | |||
118 | #define PSR_PSREN (1 << 15) | ||
119 | |||
120 | #define FIC_TX2COUNT(x) (((x) >> 24) & 0xf) | ||
121 | #define FIC_TX1COUNT(x) (((x) >> 16) & 0xf) | ||
122 | |||
123 | #define FIC_TXFLUSH (1 << 15) | ||
124 | #define FIC_RXFLUSH (1 << 7) | ||
125 | #define FIC_TXCOUNT(x) (((x) >> 8) & 0xf) | ||
126 | #define FIC_RXCOUNT(x) (((x) >> 0) & 0xf) | ||
127 | #define FICS_TXCOUNT(x) (((x) >> 8) & 0x7f) | ||
128 | 26 | ||
129 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | 27 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) |
130 | 28 | ||
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index e7c1009a1e1d..45fbe2b3727f 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c | |||
@@ -8,6 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include "../codecs/wm8994.h" | 10 | #include "../codecs/wm8994.h" |
11 | #include <sound/pcm_params.h> | ||
11 | 12 | ||
12 | /* | 13 | /* |
13 | * Default CFG switch settings to use this driver: | 14 | * Default CFG switch settings to use this driver: |
@@ -44,7 +45,9 @@ static int smdk_hw_params(struct snd_pcm_substream *substream, | |||
44 | int ret; | 45 | int ret; |
45 | 46 | ||
46 | /* AIF1CLK should be >=3MHz for optimal performance */ | 47 | /* AIF1CLK should be >=3MHz for optimal performance */ |
47 | if (params_rate(params) == 8000 || params_rate(params) == 11025) | 48 | if (params_format(params) == SNDRV_PCM_FORMAT_S24_LE) |
49 | pll_out = params_rate(params) * 384; | ||
50 | else if (params_rate(params) == 8000 || params_rate(params) == 11025) | ||
48 | pll_out = params_rate(params) * 512; | 51 | pll_out = params_rate(params) * 512; |
49 | else | 52 | else |
50 | pll_out = params_rate(params) * 256; | 53 | pll_out = params_rate(params) * 256; |
diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c new file mode 100644 index 000000000000..5f2111685480 --- /dev/null +++ b/sound/soc/samsung/smdk_wm8994pcm.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * sound/soc/samsung/smdk_wm8994pcm.c | ||
3 | * | ||
4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd | ||
5 | * http://www.samsung.com | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | #include <sound/soc.h> | ||
13 | #include <sound/pcm.h> | ||
14 | #include <sound/pcm_params.h> | ||
15 | |||
16 | #include "../codecs/wm8994.h" | ||
17 | #include "dma.h" | ||
18 | #include "pcm.h" | ||
19 | |||
20 | /* | ||
21 | * Board Settings: | ||
22 | * o '1' means 'ON' | ||
23 | * o '0' means 'OFF' | ||
24 | * o 'X' means 'Don't care' | ||
25 | * | ||
26 | * SMDKC210, SMDKV310: CFG3- 1001, CFG5-1000, CFG7-111111 | ||
27 | */ | ||
28 | |||
29 | /* | ||
30 | * Configure audio route as :- | ||
31 | * $ amixer sset 'DAC1' on,on | ||
32 | * $ amixer sset 'Right Headphone Mux' 'DAC' | ||
33 | * $ amixer sset 'Left Headphone Mux' 'DAC' | ||
34 | * $ amixer sset 'DAC1R Mixer AIF1.1' on | ||
35 | * $ amixer sset 'DAC1L Mixer AIF1.1' on | ||
36 | * $ amixer sset 'IN2L' on | ||
37 | * $ amixer sset 'IN2L PGA IN2LN' on | ||
38 | * $ amixer sset 'MIXINL IN2L' on | ||
39 | * $ amixer sset 'AIF1ADC1L Mixer ADC/DMIC' on | ||
40 | * $ amixer sset 'IN2R' on | ||
41 | * $ amixer sset 'IN2R PGA IN2RN' on | ||
42 | * $ amixer sset 'MIXINR IN2R' on | ||
43 | * $ amixer sset 'AIF1ADC1R Mixer ADC/DMIC' on | ||
44 | */ | ||
45 | |||
46 | /* SMDK has a 16.9344MHZ crystal attached to WM8994 */ | ||
47 | #define SMDK_WM8994_FREQ 16934400 | ||
48 | |||
49 | static int smdk_wm8994_pcm_hw_params(struct snd_pcm_substream *substream, | ||
50 | struct snd_pcm_hw_params *params) | ||
51 | { | ||
52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
53 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
54 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
55 | unsigned long mclk_freq; | ||
56 | int rfs, ret; | ||
57 | |||
58 | switch(params_rate(params)) { | ||
59 | case 8000: | ||
60 | rfs = 512; | ||
61 | break; | ||
62 | default: | ||
63 | dev_err(cpu_dai->dev, "%s:%d Sampling Rate %u not supported!\n", | ||
64 | __func__, __LINE__, params_rate(params)); | ||
65 | return -EINVAL; | ||
66 | } | ||
67 | |||
68 | mclk_freq = params_rate(params) * rfs; | ||
69 | |||
70 | /* Set the codec DAI configuration */ | ||
71 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | ||
72 | | SND_SOC_DAIFMT_IB_NF | ||
73 | | SND_SOC_DAIFMT_CBS_CFS); | ||
74 | if (ret < 0) | ||
75 | return ret; | ||
76 | |||
77 | /* Set the cpu DAI configuration */ | ||
78 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_B | ||
79 | | SND_SOC_DAIFMT_IB_NF | ||
80 | | SND_SOC_DAIFMT_CBS_CFS); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | |||
84 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, | ||
85 | mclk_freq, SND_SOC_CLOCK_IN); | ||
86 | if (ret < 0) | ||
87 | return ret; | ||
88 | |||
89 | ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, | ||
90 | SMDK_WM8994_FREQ, mclk_freq); | ||
91 | if (ret < 0) | ||
92 | return ret; | ||
93 | |||
94 | /* Set PCM source clock on CPU */ | ||
95 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX, | ||
96 | mclk_freq, SND_SOC_CLOCK_IN); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | /* Set SCLK_DIV for making bclk */ | ||
101 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs); | ||
102 | if (ret < 0) | ||
103 | return ret; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static struct snd_soc_ops smdk_wm8994_pcm_ops = { | ||
109 | .hw_params = smdk_wm8994_pcm_hw_params, | ||
110 | }; | ||
111 | |||
112 | static struct snd_soc_dai_link smdk_dai[] = { | ||
113 | { | ||
114 | .name = "WM8994 PAIF PCM", | ||
115 | .stream_name = "Primary PCM", | ||
116 | .cpu_dai_name = "samsung-pcm.0", | ||
117 | .codec_dai_name = "wm8994-aif1", | ||
118 | .platform_name = "samsung-audio", | ||
119 | .codec_name = "wm8994-codec", | ||
120 | .ops = &smdk_wm8994_pcm_ops, | ||
121 | }, | ||
122 | }; | ||
123 | |||
124 | static struct snd_soc_card smdk_pcm = { | ||
125 | .name = "SMDK-PCM", | ||
126 | .dai_link = smdk_dai, | ||
127 | .num_links = 1, | ||
128 | }; | ||
129 | |||
130 | static int __devinit snd_smdk_probe(struct platform_device *pdev) | ||
131 | { | ||
132 | int ret = 0; | ||
133 | |||
134 | smdk_pcm.dev = &pdev->dev; | ||
135 | ret = snd_soc_register_card(&smdk_pcm); | ||
136 | if (ret) { | ||
137 | dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int __devexit snd_smdk_remove(struct platform_device *pdev) | ||
145 | { | ||
146 | snd_soc_unregister_card(&smdk_pcm); | ||
147 | platform_set_drvdata(pdev, NULL); | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static struct platform_driver snd_smdk_driver = { | ||
152 | .driver = { | ||
153 | .owner = THIS_MODULE, | ||
154 | .name = "samsung-smdk-pcm", | ||
155 | }, | ||
156 | .probe = snd_smdk_probe, | ||
157 | .remove = __devexit_p(snd_smdk_remove), | ||
158 | }; | ||
159 | |||
160 | static int __init smdk_audio_init(void) | ||
161 | { | ||
162 | return platform_driver_register(&snd_smdk_driver); | ||
163 | } | ||
164 | |||
165 | module_init(smdk_audio_init); | ||
166 | |||
167 | static void __exit smdk_audio_exit(void) | ||
168 | { | ||
169 | platform_driver_unregister(&snd_smdk_driver); | ||
170 | } | ||
171 | |||
172 | module_exit(smdk_audio_exit); | ||
173 | |||
174 | MODULE_AUTHOR("Sangbeom Kim, <sbkim73@samsung.com>"); | ||
175 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994 for PCM"); | ||
176 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 360a333cb7c0..d6dee4d02036 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c | |||
@@ -20,24 +20,29 @@ | |||
20 | #define WM8915_HPSEL_GPIO 214 | 20 | #define WM8915_HPSEL_GPIO 214 |
21 | 21 | ||
22 | static int speyside_set_bias_level(struct snd_soc_card *card, | 22 | static int speyside_set_bias_level(struct snd_soc_card *card, |
23 | struct snd_soc_dapm_context *dapm, | ||
23 | enum snd_soc_bias_level level) | 24 | enum snd_soc_bias_level level) |
24 | { | 25 | { |
25 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | 26 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; |
26 | int ret; | 27 | int ret; |
27 | 28 | ||
29 | if (dapm->dev != codec_dai->dev) | ||
30 | return 0; | ||
31 | |||
28 | switch (level) { | 32 | switch (level) { |
29 | case SND_SOC_BIAS_STANDBY: | 33 | case SND_SOC_BIAS_STANDBY: |
30 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK1, | 34 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_MCLK2, |
31 | 32768, SND_SOC_CLOCK_IN); | 35 | 32768, SND_SOC_CLOCK_IN); |
32 | if (ret < 0) | 36 | if (ret < 0) |
33 | return ret; | 37 | return ret; |
34 | 38 | ||
35 | ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK1, | 39 | ret = snd_soc_dai_set_pll(codec_dai, WM8915_FLL_MCLK2, |
36 | 0, 0, 0); | 40 | 0, 0, 0); |
37 | if (ret < 0) { | 41 | if (ret < 0) { |
38 | pr_err("Failed to stop FLL\n"); | 42 | pr_err("Failed to stop FLL\n"); |
39 | return ret; | 43 | return ret; |
40 | } | 44 | } |
45 | break; | ||
41 | 46 | ||
42 | default: | 47 | default: |
43 | break; | 48 | break; |
@@ -46,6 +51,45 @@ static int speyside_set_bias_level(struct snd_soc_card *card, | |||
46 | return 0; | 51 | return 0; |
47 | } | 52 | } |
48 | 53 | ||
54 | static int speyside_set_bias_level_post(struct snd_soc_card *card, | ||
55 | struct snd_soc_dapm_context *dapm, | ||
56 | enum snd_soc_bias_level level) | ||
57 | { | ||
58 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | ||
59 | int ret; | ||
60 | |||
61 | if (dapm->dev != codec_dai->dev) | ||
62 | return 0; | ||
63 | |||
64 | switch (level) { | ||
65 | case SND_SOC_BIAS_PREPARE: | ||
66 | if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | ||
67 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
68 | WM8915_FLL_MCLK2, | ||
69 | 32768, 48000 * 256); | ||
70 | if (ret < 0) { | ||
71 | pr_err("Failed to start FLL\n"); | ||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | ret = snd_soc_dai_set_sysclk(codec_dai, | ||
76 | WM8915_SYSCLK_FLL, | ||
77 | 48000 * 256, | ||
78 | SND_SOC_CLOCK_IN); | ||
79 | if (ret < 0) | ||
80 | return ret; | ||
81 | } | ||
82 | break; | ||
83 | |||
84 | default: | ||
85 | break; | ||
86 | } | ||
87 | |||
88 | card->dapm.bias_level = level; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
49 | static int speyside_hw_params(struct snd_pcm_substream *substream, | 93 | static int speyside_hw_params(struct snd_pcm_substream *substream, |
50 | struct snd_pcm_hw_params *params) | 94 | struct snd_pcm_hw_params *params) |
51 | { | 95 | { |
@@ -66,16 +110,6 @@ static int speyside_hw_params(struct snd_pcm_substream *substream, | |||
66 | if (ret < 0) | 110 | if (ret < 0) |
67 | return ret; | 111 | return ret; |
68 | 112 | ||
69 | ret = snd_soc_dai_set_pll(codec_dai, 0, WM8915_FLL_MCLK1, | ||
70 | 32768, 256 * 48000); | ||
71 | if (ret < 0) | ||
72 | return ret; | ||
73 | |||
74 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8915_SYSCLK_FLL, | ||
75 | 256 * 48000, SND_SOC_CLOCK_IN); | ||
76 | if (ret < 0) | ||
77 | return ret; | ||
78 | |||
79 | return 0; | 113 | return 0; |
80 | } | 114 | } |
81 | 115 | ||
@@ -127,7 +161,7 @@ static int speyside_wm8915_init(struct snd_soc_pcm_runtime *rtd) | |||
127 | struct snd_soc_codec *codec = rtd->codec; | 161 | struct snd_soc_codec *codec = rtd->codec; |
128 | int ret; | 162 | int ret; |
129 | 163 | ||
130 | ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK1, 32768, 0); | 164 | ret = snd_soc_dai_set_sysclk(dai, WM8915_SYSCLK_MCLK2, 32768, 0); |
131 | if (ret < 0) | 165 | if (ret < 0) |
132 | return ret; | 166 | return ret; |
133 | 167 | ||
@@ -267,6 +301,7 @@ static struct snd_soc_card speyside = { | |||
267 | .num_configs = ARRAY_SIZE(speyside_codec_conf), | 301 | .num_configs = ARRAY_SIZE(speyside_codec_conf), |
268 | 302 | ||
269 | .set_bias_level = speyside_set_bias_level, | 303 | .set_bias_level = speyside_set_bias_level, |
304 | .set_bias_level_post = speyside_set_bias_level_post, | ||
270 | 305 | ||
271 | .controls = controls, | 306 | .controls = controls, |
272 | .num_controls = ARRAY_SIZE(controls), | 307 | .num_controls = ARRAY_SIZE(controls), |
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c new file mode 100644 index 000000000000..8ac42bf82090 --- /dev/null +++ b/sound/soc/samsung/speyside_wm8962.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * Speyside with WM8962 audio support | ||
3 | * | ||
4 | * Copyright 2011 Wolfson Microelectronics | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <sound/soc.h> | ||
13 | #include <sound/soc-dapm.h> | ||
14 | #include <sound/jack.h> | ||
15 | #include <linux/gpio.h> | ||
16 | |||
17 | #include "../codecs/wm8962.h" | ||
18 | |||
19 | static int speyside_wm8962_set_bias_level(struct snd_soc_card *card, | ||
20 | struct snd_soc_dapm_context *dapm, | ||
21 | enum snd_soc_bias_level level) | ||
22 | { | ||
23 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | ||
24 | int ret; | ||
25 | |||
26 | switch (level) { | ||
27 | case SND_SOC_BIAS_PREPARE: | ||
28 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { | ||
29 | ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL, | ||
30 | WM8962_FLL_MCLK, 32768, | ||
31 | 44100 * 256); | ||
32 | if (ret < 0) | ||
33 | pr_err("Failed to start FLL: %d\n", ret); | ||
34 | |||
35 | ret = snd_soc_dai_set_sysclk(codec_dai, | ||
36 | WM8962_SYSCLK_FLL, | ||
37 | 44100 * 256, | ||
38 | SND_SOC_CLOCK_IN); | ||
39 | if (ret < 0) { | ||
40 | pr_err("Failed to set SYSCLK: %d\n"); | ||
41 | return ret; | ||
42 | } | ||
43 | } | ||
44 | break; | ||
45 | |||
46 | default: | ||
47 | break; | ||
48 | } | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int speyside_wm8962_set_bias_level_post(struct snd_soc_card *card, | ||
54 | struct snd_soc_dapm_context *dapm, | ||
55 | enum snd_soc_bias_level level) | ||
56 | { | ||
57 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | ||
58 | int ret; | ||
59 | |||
60 | switch (level) { | ||
61 | case SND_SOC_BIAS_STANDBY: | ||
62 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, | ||
63 | 32768, SND_SOC_CLOCK_IN); | ||
64 | if (ret < 0) { | ||
65 | pr_err("Failed to switch away from FLL: %d\n", ret); | ||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | ret = snd_soc_dai_set_pll(codec_dai, WM8962_FLL, | ||
70 | 0, 0, 0); | ||
71 | if (ret < 0) { | ||
72 | pr_err("Failed to stop FLL: %d\n", ret); | ||
73 | return ret; | ||
74 | } | ||
75 | break; | ||
76 | |||
77 | default: | ||
78 | break; | ||
79 | } | ||
80 | |||
81 | dapm->bias_level = level; | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int speyside_wm8962_hw_params(struct snd_pcm_substream *substream, | ||
87 | struct snd_pcm_hw_params *params) | ||
88 | { | ||
89 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
90 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
91 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
92 | int ret; | ||
93 | |||
94 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ||
95 | | SND_SOC_DAIFMT_NB_NF | ||
96 | | SND_SOC_DAIFMT_CBM_CFM); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ||
101 | | SND_SOC_DAIFMT_NB_NF | ||
102 | | SND_SOC_DAIFMT_CBM_CFM); | ||
103 | if (ret < 0) | ||
104 | return ret; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static struct snd_soc_ops speyside_wm8962_ops = { | ||
110 | .hw_params = speyside_wm8962_hw_params, | ||
111 | }; | ||
112 | |||
113 | static struct snd_soc_dai_link speyside_wm8962_dai[] = { | ||
114 | { | ||
115 | .name = "CPU", | ||
116 | .stream_name = "CPU", | ||
117 | .cpu_dai_name = "samsung-i2s.0", | ||
118 | .codec_dai_name = "wm8962", | ||
119 | .platform_name = "samsung-audio", | ||
120 | .codec_name = "wm8962.1-001a", | ||
121 | .ops = &speyside_wm8962_ops, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | static const struct snd_kcontrol_new controls[] = { | ||
126 | SOC_DAPM_PIN_SWITCH("Main Speaker"), | ||
127 | }; | ||
128 | |||
129 | static struct snd_soc_dapm_widget widgets[] = { | ||
130 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
131 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
132 | |||
133 | SND_SOC_DAPM_MIC("DMIC", NULL), | ||
134 | |||
135 | SND_SOC_DAPM_SPK("Main Speaker", NULL), | ||
136 | }; | ||
137 | |||
138 | static struct snd_soc_dapm_route audio_paths[] = { | ||
139 | { "Headphone", NULL, "HPOUTL" }, | ||
140 | { "Headphone", NULL, "HPOUTR" }, | ||
141 | |||
142 | { "Main Speaker", NULL, "SPKOUTL" }, | ||
143 | { "Main Speaker", NULL, "SPKOUTR" }, | ||
144 | |||
145 | { "MICBIAS", NULL, "Headset Mic" }, | ||
146 | { "IN4L", NULL, "MICBIAS" }, | ||
147 | { "IN4R", NULL, "MICBIAS" }, | ||
148 | |||
149 | { "MICBIAS", NULL, "DMIC" }, | ||
150 | { "DMICDAT", NULL, "MICBIAS" }, | ||
151 | }; | ||
152 | |||
153 | static struct snd_soc_jack speyside_wm8962_headset; | ||
154 | |||
155 | /* Headset jack detection DAPM pins */ | ||
156 | static struct snd_soc_jack_pin speyside_wm8962_headset_pins[] = { | ||
157 | { | ||
158 | .pin = "Headset Mic", | ||
159 | .mask = SND_JACK_MICROPHONE, | ||
160 | }, | ||
161 | { | ||
162 | .pin = "Headphone", | ||
163 | .mask = SND_JACK_MICROPHONE, | ||
164 | }, | ||
165 | }; | ||
166 | |||
167 | static int speyside_wm8962_late_probe(struct snd_soc_card *card) | ||
168 | { | ||
169 | struct snd_soc_codec *codec = card->rtd[0].codec; | ||
170 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | ||
171 | int ret; | ||
172 | |||
173 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, | ||
174 | 32768, SND_SOC_CLOCK_IN); | ||
175 | if (ret < 0) | ||
176 | return ret; | ||
177 | |||
178 | ret = snd_soc_jack_new(codec, "Headset", | ||
179 | SND_JACK_HEADSET | SND_JACK_BTN_0, | ||
180 | &speyside_wm8962_headset); | ||
181 | if (ret) | ||
182 | return ret; | ||
183 | |||
184 | ret = snd_soc_jack_add_pins(&speyside_wm8962_headset, | ||
185 | ARRAY_SIZE(speyside_wm8962_headset_pins), | ||
186 | speyside_wm8962_headset_pins); | ||
187 | if (ret) | ||
188 | return ret; | ||
189 | |||
190 | wm8962_mic_detect(codec, &speyside_wm8962_headset); | ||
191 | |||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static struct snd_soc_card speyside_wm8962 = { | ||
196 | .name = "Speyside WM8962", | ||
197 | .dai_link = speyside_wm8962_dai, | ||
198 | .num_links = ARRAY_SIZE(speyside_wm8962_dai), | ||
199 | |||
200 | .set_bias_level = speyside_wm8962_set_bias_level, | ||
201 | .set_bias_level_post = speyside_wm8962_set_bias_level_post, | ||
202 | |||
203 | .controls = controls, | ||
204 | .num_controls = ARRAY_SIZE(controls), | ||
205 | .dapm_widgets = widgets, | ||
206 | .num_dapm_widgets = ARRAY_SIZE(widgets), | ||
207 | .dapm_routes = audio_paths, | ||
208 | .num_dapm_routes = ARRAY_SIZE(audio_paths), | ||
209 | |||
210 | .late_probe = speyside_wm8962_late_probe, | ||
211 | }; | ||
212 | |||
213 | static __devinit int speyside_wm8962_probe(struct platform_device *pdev) | ||
214 | { | ||
215 | struct snd_soc_card *card = &speyside_wm8962; | ||
216 | int ret; | ||
217 | |||
218 | card->dev = &pdev->dev; | ||
219 | |||
220 | ret = snd_soc_register_card(card); | ||
221 | if (ret) { | ||
222 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
223 | ret); | ||
224 | return ret; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int __devexit speyside_wm8962_remove(struct platform_device *pdev) | ||
231 | { | ||
232 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
233 | |||
234 | snd_soc_unregister_card(card); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static struct platform_driver speyside_wm8962_driver = { | ||
240 | .driver = { | ||
241 | .name = "speyside-wm8962", | ||
242 | .owner = THIS_MODULE, | ||
243 | .pm = &snd_soc_pm_ops, | ||
244 | }, | ||
245 | .probe = speyside_wm8962_probe, | ||
246 | .remove = __devexit_p(speyside_wm8962_remove), | ||
247 | }; | ||
248 | |||
249 | static int __init speyside_wm8962_audio_init(void) | ||
250 | { | ||
251 | return platform_driver_register(&speyside_wm8962_driver); | ||
252 | } | ||
253 | module_init(speyside_wm8962_audio_init); | ||
254 | |||
255 | static void __exit speyside_wm8962_audio_exit(void) | ||
256 | { | ||
257 | platform_driver_unregister(&speyside_wm8962_driver); | ||
258 | } | ||
259 | module_exit(speyside_wm8962_audio_exit); | ||
260 | |||
261 | MODULE_DESCRIPTION("Speyside WM8962 audio support"); | ||
262 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
263 | MODULE_LICENSE("GPL"); | ||
264 | MODULE_ALIAS("platform:speyside-wm8962"); | ||
diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index c326d29992fe..db74005f37ce 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c | |||
@@ -327,10 +327,10 @@ static void camelot_pcm_free(struct snd_pcm *pcm) | |||
327 | snd_pcm_lib_preallocate_free_for_all(pcm); | 327 | snd_pcm_lib_preallocate_free_for_all(pcm); |
328 | } | 328 | } |
329 | 329 | ||
330 | static int camelot_pcm_new(struct snd_card *card, | 330 | static int camelot_pcm_new(struct snd_soc_pcm_runtime *rtd) |
331 | struct snd_soc_dai *dai, | ||
332 | struct snd_pcm *pcm) | ||
333 | { | 331 | { |
332 | struct snd_pcm *pcm = rtd->pcm; | ||
333 | |||
334 | /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel | 334 | /* dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel |
335 | * in MMAP mode (i.e. aplay -M) | 335 | * in MMAP mode (i.e. aplay -M) |
336 | */ | 336 | */ |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 4a9da6b5f4e1..8e112ccffb13 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -118,10 +118,38 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena | |||
118 | /* | 118 | /* |
119 | * FSI driver use below type name for variable | 119 | * FSI driver use below type name for variable |
120 | * | 120 | * |
121 | * xxx_len : data length | ||
122 | * xxx_width : data width | ||
123 | * xxx_offset : data offset | ||
124 | * xxx_num : number of data | 121 | * xxx_num : number of data |
122 | * xxx_pos : position of data | ||
123 | * xxx_capa : capacity of data | ||
124 | */ | ||
125 | |||
126 | /* | ||
127 | * period/frame/sample image | ||
128 | * | ||
129 | * ex) PCM (2ch) | ||
130 | * | ||
131 | * period pos period pos | ||
132 | * [n] [n + 1] | ||
133 | * |<-------------------- period--------------------->| | ||
134 | * ==|============================================ ... =|== | ||
135 | * | | | ||
136 | * ||<----- frame ----->|<------ frame ----->| ... | | ||
137 | * |+--------------------+--------------------+- ... | | ||
138 | * ||[ sample ][ sample ]|[ sample ][ sample ]| ... | | ||
139 | * |+--------------------+--------------------+- ... | | ||
140 | * ==|============================================ ... =|== | ||
141 | */ | ||
142 | |||
143 | /* | ||
144 | * FSI FIFO image | ||
145 | * | ||
146 | * | | | ||
147 | * | | | ||
148 | * | [ sample ] | | ||
149 | * | [ sample ] | | ||
150 | * | [ sample ] | | ||
151 | * | [ sample ] | | ||
152 | * --> go to codecs | ||
125 | */ | 153 | */ |
126 | 154 | ||
127 | /* | 155 | /* |
@@ -131,12 +159,11 @@ typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int ena | |||
131 | struct fsi_stream { | 159 | struct fsi_stream { |
132 | struct snd_pcm_substream *substream; | 160 | struct snd_pcm_substream *substream; |
133 | 161 | ||
134 | int fifo_max_num; | 162 | int fifo_sample_capa; /* sample capacity of FSI FIFO */ |
135 | 163 | int buff_sample_capa; /* sample capacity of ALSA buffer */ | |
136 | int buff_offset; | 164 | int buff_sample_pos; /* sample position of ALSA buffer */ |
137 | int buff_len; | 165 | int period_samples; /* sample number / 1 period */ |
138 | int period_len; | 166 | int period_pos; /* current period position */ |
139 | int period_num; | ||
140 | 167 | ||
141 | int uerr_num; | 168 | int uerr_num; |
142 | int oerr_num; | 169 | int oerr_num; |
@@ -149,17 +176,14 @@ struct fsi_priv { | |||
149 | struct fsi_stream playback; | 176 | struct fsi_stream playback; |
150 | struct fsi_stream capture; | 177 | struct fsi_stream capture; |
151 | 178 | ||
179 | u32 do_fmt; | ||
180 | u32 di_fmt; | ||
181 | |||
152 | int chan_num:16; | 182 | int chan_num:16; |
153 | int clk_master:1; | 183 | int clk_master:1; |
184 | int spdif:1; | ||
154 | 185 | ||
155 | long rate; | 186 | long rate; |
156 | |||
157 | /* for suspend/resume */ | ||
158 | u32 saved_do_fmt; | ||
159 | u32 saved_di_fmt; | ||
160 | u32 saved_ckg1; | ||
161 | u32 saved_ckg2; | ||
162 | u32 saved_out_sel; | ||
163 | }; | 187 | }; |
164 | 188 | ||
165 | struct fsi_core { | 189 | struct fsi_core { |
@@ -180,14 +204,6 @@ struct fsi_master { | |||
180 | struct fsi_core *core; | 204 | struct fsi_core *core; |
181 | struct sh_fsi_platform_info *info; | 205 | struct sh_fsi_platform_info *info; |
182 | spinlock_t lock; | 206 | spinlock_t lock; |
183 | |||
184 | /* for suspend/resume */ | ||
185 | u32 saved_a_mclk; | ||
186 | u32 saved_b_mclk; | ||
187 | u32 saved_iemsk; | ||
188 | u32 saved_imsk; | ||
189 | u32 saved_clk_rst; | ||
190 | u32 saved_soft_rst; | ||
191 | }; | 207 | }; |
192 | 208 | ||
193 | /* | 209 | /* |
@@ -271,6 +287,11 @@ static int fsi_is_port_a(struct fsi_priv *fsi) | |||
271 | return fsi->master->base == fsi->base; | 287 | return fsi->master->base == fsi->base; |
272 | } | 288 | } |
273 | 289 | ||
290 | static int fsi_is_spdif(struct fsi_priv *fsi) | ||
291 | { | ||
292 | return fsi->spdif; | ||
293 | } | ||
294 | |||
274 | static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) | 295 | static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) |
275 | { | 296 | { |
276 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 297 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
@@ -342,28 +363,59 @@ static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) | |||
342 | return shift; | 363 | return shift; |
343 | } | 364 | } |
344 | 365 | ||
366 | static int fsi_frame2sample(struct fsi_priv *fsi, int frames) | ||
367 | { | ||
368 | return frames * fsi->chan_num; | ||
369 | } | ||
370 | |||
371 | static int fsi_sample2frame(struct fsi_priv *fsi, int samples) | ||
372 | { | ||
373 | return samples / fsi->chan_num; | ||
374 | } | ||
375 | |||
376 | static int fsi_stream_is_working(struct fsi_priv *fsi, | ||
377 | int is_play) | ||
378 | { | ||
379 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
380 | struct fsi_master *master = fsi_get_master(fsi); | ||
381 | unsigned long flags; | ||
382 | int ret; | ||
383 | |||
384 | spin_lock_irqsave(&master->lock, flags); | ||
385 | ret = !!io->substream; | ||
386 | spin_unlock_irqrestore(&master->lock, flags); | ||
387 | |||
388 | return ret; | ||
389 | } | ||
390 | |||
345 | static void fsi_stream_push(struct fsi_priv *fsi, | 391 | static void fsi_stream_push(struct fsi_priv *fsi, |
346 | int is_play, | 392 | int is_play, |
347 | struct snd_pcm_substream *substream, | 393 | struct snd_pcm_substream *substream) |
348 | u32 buffer_len, | ||
349 | u32 period_len) | ||
350 | { | 394 | { |
351 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 395 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
396 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
397 | struct fsi_master *master = fsi_get_master(fsi); | ||
398 | unsigned long flags; | ||
352 | 399 | ||
400 | spin_lock_irqsave(&master->lock, flags); | ||
353 | io->substream = substream; | 401 | io->substream = substream; |
354 | io->buff_len = buffer_len; | 402 | io->buff_sample_capa = fsi_frame2sample(fsi, runtime->buffer_size); |
355 | io->buff_offset = 0; | 403 | io->buff_sample_pos = 0; |
356 | io->period_len = period_len; | 404 | io->period_samples = fsi_frame2sample(fsi, runtime->period_size); |
357 | io->period_num = 0; | 405 | io->period_pos = 0; |
358 | io->oerr_num = -1; /* ignore 1st err */ | 406 | io->oerr_num = -1; /* ignore 1st err */ |
359 | io->uerr_num = -1; /* ignore 1st err */ | 407 | io->uerr_num = -1; /* ignore 1st err */ |
408 | spin_unlock_irqrestore(&master->lock, flags); | ||
360 | } | 409 | } |
361 | 410 | ||
362 | static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | 411 | static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) |
363 | { | 412 | { |
364 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 413 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
365 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); | 414 | struct snd_soc_dai *dai = fsi_get_dai(io->substream); |
415 | struct fsi_master *master = fsi_get_master(fsi); | ||
416 | unsigned long flags; | ||
366 | 417 | ||
418 | spin_lock_irqsave(&master->lock, flags); | ||
367 | 419 | ||
368 | if (io->oerr_num > 0) | 420 | if (io->oerr_num > 0) |
369 | dev_err(dai->dev, "over_run = %d\n", io->oerr_num); | 421 | dev_err(dai->dev, "over_run = %d\n", io->oerr_num); |
@@ -372,47 +424,27 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | |||
372 | dev_err(dai->dev, "under_run = %d\n", io->uerr_num); | 424 | dev_err(dai->dev, "under_run = %d\n", io->uerr_num); |
373 | 425 | ||
374 | io->substream = NULL; | 426 | io->substream = NULL; |
375 | io->buff_len = 0; | 427 | io->buff_sample_capa = 0; |
376 | io->buff_offset = 0; | 428 | io->buff_sample_pos = 0; |
377 | io->period_len = 0; | 429 | io->period_samples = 0; |
378 | io->period_num = 0; | 430 | io->period_pos = 0; |
379 | io->oerr_num = 0; | 431 | io->oerr_num = 0; |
380 | io->uerr_num = 0; | 432 | io->uerr_num = 0; |
433 | spin_unlock_irqrestore(&master->lock, flags); | ||
381 | } | 434 | } |
382 | 435 | ||
383 | static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) | 436 | static int fsi_get_current_fifo_samples(struct fsi_priv *fsi, int is_play) |
384 | { | 437 | { |
385 | u32 status; | 438 | u32 status; |
386 | int data_num; | 439 | int frames; |
387 | 440 | ||
388 | status = is_play ? | 441 | status = is_play ? |
389 | fsi_reg_read(fsi, DOFF_ST) : | 442 | fsi_reg_read(fsi, DOFF_ST) : |
390 | fsi_reg_read(fsi, DIFF_ST); | 443 | fsi_reg_read(fsi, DIFF_ST); |
391 | 444 | ||
392 | data_num = 0x1ff & (status >> 8); | 445 | frames = 0x1ff & (status >> 8); |
393 | data_num *= fsi->chan_num; | ||
394 | |||
395 | return data_num; | ||
396 | } | ||
397 | |||
398 | static int fsi_len2num(int len, int width) | ||
399 | { | ||
400 | return len / width; | ||
401 | } | ||
402 | |||
403 | #define fsi_num2offset(a, b) fsi_num2len(a, b) | ||
404 | static int fsi_num2len(int num, int width) | ||
405 | { | ||
406 | return num * width; | ||
407 | } | ||
408 | |||
409 | static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play) | ||
410 | { | ||
411 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
412 | struct snd_pcm_substream *substream = io->substream; | ||
413 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
414 | 446 | ||
415 | return frames_to_bytes(runtime, 1) / fsi->chan_num; | 447 | return fsi_frame2sample(fsi, frames); |
416 | } | 448 | } |
417 | 449 | ||
418 | static void fsi_count_fifo_err(struct fsi_priv *fsi) | 450 | static void fsi_count_fifo_err(struct fsi_priv *fsi) |
@@ -444,8 +476,10 @@ static u8 *fsi_dma_get_area(struct fsi_priv *fsi, int stream) | |||
444 | { | 476 | { |
445 | int is_play = fsi_stream_is_play(stream); | 477 | int is_play = fsi_stream_is_play(stream); |
446 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 478 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
479 | struct snd_pcm_runtime *runtime = io->substream->runtime; | ||
447 | 480 | ||
448 | return io->substream->runtime->dma_area + io->buff_offset; | 481 | return runtime->dma_area + |
482 | samples_to_bytes(runtime, io->buff_sample_pos); | ||
449 | } | 483 | } |
450 | 484 | ||
451 | static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) | 485 | static void fsi_dma_soft_push16(struct fsi_priv *fsi, int num) |
@@ -559,37 +593,94 @@ static void fsi_spdif_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
559 | /* | 593 | /* |
560 | * clock function | 594 | * clock function |
561 | */ | 595 | */ |
562 | #define fsi_module_init(m, d) __fsi_module_clk_ctrl(m, d, 1) | 596 | static int fsi_set_master_clk(struct device *dev, struct fsi_priv *fsi, |
563 | #define fsi_module_kill(m, d) __fsi_module_clk_ctrl(m, d, 0) | 597 | long rate, int enable) |
564 | static void __fsi_module_clk_ctrl(struct fsi_master *master, | ||
565 | struct device *dev, | ||
566 | int enable) | ||
567 | { | 598 | { |
568 | pm_runtime_get_sync(dev); | 599 | struct fsi_master *master = fsi_get_master(fsi); |
600 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
601 | int fsi_ver = master->core->ver; | ||
602 | int ret; | ||
569 | 603 | ||
570 | if (enable) { | 604 | ret = set_rate(dev, fsi_is_port_a(fsi), rate, enable); |
571 | /* enable only SR */ | 605 | if (ret < 0) /* error */ |
572 | fsi_master_mask_set(master, SOFT_RST, FSISR, FSISR); | 606 | return ret; |
573 | fsi_master_mask_set(master, SOFT_RST, PASR | PBSR, 0); | 607 | |
574 | } else { | 608 | if (!enable) |
575 | /* clear all registers */ | 609 | return 0; |
576 | fsi_master_mask_set(master, SOFT_RST, FSISR, 0); | 610 | |
611 | if (ret > 0) { | ||
612 | u32 data = 0; | ||
613 | |||
614 | switch (ret & SH_FSI_ACKMD_MASK) { | ||
615 | default: | ||
616 | /* FALL THROUGH */ | ||
617 | case SH_FSI_ACKMD_512: | ||
618 | data |= (0x0 << 12); | ||
619 | break; | ||
620 | case SH_FSI_ACKMD_256: | ||
621 | data |= (0x1 << 12); | ||
622 | break; | ||
623 | case SH_FSI_ACKMD_128: | ||
624 | data |= (0x2 << 12); | ||
625 | break; | ||
626 | case SH_FSI_ACKMD_64: | ||
627 | data |= (0x3 << 12); | ||
628 | break; | ||
629 | case SH_FSI_ACKMD_32: | ||
630 | if (fsi_ver < 2) | ||
631 | dev_err(dev, "unsupported ACKMD\n"); | ||
632 | else | ||
633 | data |= (0x4 << 12); | ||
634 | break; | ||
635 | } | ||
636 | |||
637 | switch (ret & SH_FSI_BPFMD_MASK) { | ||
638 | default: | ||
639 | /* FALL THROUGH */ | ||
640 | case SH_FSI_BPFMD_32: | ||
641 | data |= (0x0 << 8); | ||
642 | break; | ||
643 | case SH_FSI_BPFMD_64: | ||
644 | data |= (0x1 << 8); | ||
645 | break; | ||
646 | case SH_FSI_BPFMD_128: | ||
647 | data |= (0x2 << 8); | ||
648 | break; | ||
649 | case SH_FSI_BPFMD_256: | ||
650 | data |= (0x3 << 8); | ||
651 | break; | ||
652 | case SH_FSI_BPFMD_512: | ||
653 | data |= (0x4 << 8); | ||
654 | break; | ||
655 | case SH_FSI_BPFMD_16: | ||
656 | if (fsi_ver < 2) | ||
657 | dev_err(dev, "unsupported ACKMD\n"); | ||
658 | else | ||
659 | data |= (0x7 << 8); | ||
660 | break; | ||
661 | } | ||
662 | |||
663 | fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); | ||
664 | udelay(10); | ||
665 | ret = 0; | ||
577 | } | 666 | } |
578 | 667 | ||
579 | pm_runtime_put_sync(dev); | 668 | return ret; |
580 | } | 669 | } |
581 | 670 | ||
582 | #define fsi_port_start(f) __fsi_port_clk_ctrl(f, 1) | 671 | #define fsi_port_start(f, i) __fsi_port_clk_ctrl(f, i, 1) |
583 | #define fsi_port_stop(f) __fsi_port_clk_ctrl(f, 0) | 672 | #define fsi_port_stop(f, i) __fsi_port_clk_ctrl(f, i, 0) |
584 | static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable) | 673 | static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int is_play, int enable) |
585 | { | 674 | { |
586 | struct fsi_master *master = fsi_get_master(fsi); | 675 | struct fsi_master *master = fsi_get_master(fsi); |
587 | u32 soft = fsi_is_port_a(fsi) ? PASR : PBSR; | ||
588 | u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; | 676 | u32 clk = fsi_is_port_a(fsi) ? CRA : CRB; |
589 | int is_master = fsi_is_clk_master(fsi); | ||
590 | 677 | ||
591 | fsi_master_mask_set(master, SOFT_RST, soft, (enable) ? soft : 0); | 678 | if (enable) |
592 | if (is_master) | 679 | fsi_irq_enable(fsi, is_play); |
680 | else | ||
681 | fsi_irq_disable(fsi, is_play); | ||
682 | |||
683 | if (fsi_is_clk_master(fsi)) | ||
593 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); | 684 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); |
594 | } | 685 | } |
595 | 686 | ||
@@ -598,18 +689,19 @@ static void __fsi_port_clk_ctrl(struct fsi_priv *fsi, int enable) | |||
598 | */ | 689 | */ |
599 | static void fsi_fifo_init(struct fsi_priv *fsi, | 690 | static void fsi_fifo_init(struct fsi_priv *fsi, |
600 | int is_play, | 691 | int is_play, |
601 | struct snd_soc_dai *dai) | 692 | struct device *dev) |
602 | { | 693 | { |
603 | struct fsi_master *master = fsi_get_master(fsi); | 694 | struct fsi_master *master = fsi_get_master(fsi); |
604 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 695 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
605 | u32 shift, i; | 696 | u32 shift, i; |
697 | int frame_capa; | ||
606 | 698 | ||
607 | /* get on-chip RAM capacity */ | 699 | /* get on-chip RAM capacity */ |
608 | shift = fsi_master_read(master, FIFO_SZ); | 700 | shift = fsi_master_read(master, FIFO_SZ); |
609 | shift >>= fsi_get_port_shift(fsi, is_play); | 701 | shift >>= fsi_get_port_shift(fsi, is_play); |
610 | shift &= FIFO_SZ_MASK; | 702 | shift &= FIFO_SZ_MASK; |
611 | io->fifo_max_num = 256 << shift; | 703 | frame_capa = 256 << shift; |
612 | dev_dbg(dai->dev, "fifo = %d words\n", io->fifo_max_num); | 704 | dev_dbg(dev, "fifo = %d words\n", frame_capa); |
613 | 705 | ||
614 | /* | 706 | /* |
615 | * The maximum number of sample data varies depending | 707 | * The maximum number of sample data varies depending |
@@ -631,9 +723,11 @@ static void fsi_fifo_init(struct fsi_priv *fsi, | |||
631 | * 8 channels: 32 ( 32 x 8 = 256) | 723 | * 8 channels: 32 ( 32 x 8 = 256) |
632 | */ | 724 | */ |
633 | for (i = 1; i < fsi->chan_num; i <<= 1) | 725 | for (i = 1; i < fsi->chan_num; i <<= 1) |
634 | io->fifo_max_num >>= 1; | 726 | frame_capa >>= 1; |
635 | dev_dbg(dai->dev, "%d channel %d store\n", | 727 | dev_dbg(dev, "%d channel %d store\n", |
636 | fsi->chan_num, io->fifo_max_num); | 728 | fsi->chan_num, frame_capa); |
729 | |||
730 | io->fifo_sample_capa = fsi_frame2sample(fsi, frame_capa); | ||
637 | 731 | ||
638 | /* | 732 | /* |
639 | * set interrupt generation factor | 733 | * set interrupt generation factor |
@@ -654,10 +748,10 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
654 | struct snd_pcm_substream *substream = NULL; | 748 | struct snd_pcm_substream *substream = NULL; |
655 | int is_play = fsi_stream_is_play(stream); | 749 | int is_play = fsi_stream_is_play(stream); |
656 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | 750 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); |
657 | int data_residue_num; | 751 | int sample_residues; |
658 | int data_num; | 752 | int sample_width; |
659 | int data_num_max; | 753 | int samples; |
660 | int ch_width; | 754 | int samples_max; |
661 | int over_period; | 755 | int over_period; |
662 | void (*fn)(struct fsi_priv *fsi, int size); | 756 | void (*fn)(struct fsi_priv *fsi, int size); |
663 | 757 | ||
@@ -673,36 +767,35 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
673 | /* FSI FIFO has limit. | 767 | /* FSI FIFO has limit. |
674 | * So, this driver can not send periods data at a time | 768 | * So, this driver can not send periods data at a time |
675 | */ | 769 | */ |
676 | if (io->buff_offset >= | 770 | if (io->buff_sample_pos >= |
677 | fsi_num2offset(io->period_num + 1, io->period_len)) { | 771 | io->period_samples * (io->period_pos + 1)) { |
678 | 772 | ||
679 | over_period = 1; | 773 | over_period = 1; |
680 | io->period_num = (io->period_num + 1) % runtime->periods; | 774 | io->period_pos = (io->period_pos + 1) % runtime->periods; |
681 | 775 | ||
682 | if (0 == io->period_num) | 776 | if (0 == io->period_pos) |
683 | io->buff_offset = 0; | 777 | io->buff_sample_pos = 0; |
684 | } | 778 | } |
685 | 779 | ||
686 | /* get 1 channel data width */ | 780 | /* get 1 sample data width */ |
687 | ch_width = fsi_get_frame_width(fsi, is_play); | 781 | sample_width = samples_to_bytes(runtime, 1); |
688 | 782 | ||
689 | /* get residue data number of alsa */ | 783 | /* get number of residue samples */ |
690 | data_residue_num = fsi_len2num(io->buff_len - io->buff_offset, | 784 | sample_residues = io->buff_sample_capa - io->buff_sample_pos; |
691 | ch_width); | ||
692 | 785 | ||
693 | if (is_play) { | 786 | if (is_play) { |
694 | /* | 787 | /* |
695 | * for play-back | 788 | * for play-back |
696 | * | 789 | * |
697 | * data_num_max : number of FSI fifo free space | 790 | * samples_max : number of FSI fifo free samples space |
698 | * data_num : number of ALSA residue data | 791 | * samples : number of ALSA residue samples |
699 | */ | 792 | */ |
700 | data_num_max = io->fifo_max_num * fsi->chan_num; | 793 | samples_max = io->fifo_sample_capa; |
701 | data_num_max -= fsi_get_fifo_data_num(fsi, is_play); | 794 | samples_max -= fsi_get_current_fifo_samples(fsi, is_play); |
702 | 795 | ||
703 | data_num = data_residue_num; | 796 | samples = sample_residues; |
704 | 797 | ||
705 | switch (ch_width) { | 798 | switch (sample_width) { |
706 | case 2: | 799 | case 2: |
707 | fn = fsi_dma_soft_push16; | 800 | fn = fsi_dma_soft_push16; |
708 | break; | 801 | break; |
@@ -716,13 +809,13 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
716 | /* | 809 | /* |
717 | * for capture | 810 | * for capture |
718 | * | 811 | * |
719 | * data_num_max : number of ALSA free space | 812 | * samples_max : number of ALSA free samples space |
720 | * data_num : number of data in FSI fifo | 813 | * samples : number of samples in FSI fifo |
721 | */ | 814 | */ |
722 | data_num_max = data_residue_num; | 815 | samples_max = sample_residues; |
723 | data_num = fsi_get_fifo_data_num(fsi, is_play); | 816 | samples = fsi_get_current_fifo_samples(fsi, is_play); |
724 | 817 | ||
725 | switch (ch_width) { | 818 | switch (sample_width) { |
726 | case 2: | 819 | case 2: |
727 | fn = fsi_dma_soft_pop16; | 820 | fn = fsi_dma_soft_pop16; |
728 | break; | 821 | break; |
@@ -734,12 +827,12 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
734 | } | 827 | } |
735 | } | 828 | } |
736 | 829 | ||
737 | data_num = min(data_num, data_num_max); | 830 | samples = min(samples, samples_max); |
738 | 831 | ||
739 | fn(fsi, data_num); | 832 | fn(fsi, samples); |
740 | 833 | ||
741 | /* update buff_offset */ | 834 | /* update buff_sample_pos */ |
742 | io->buff_offset += fsi_num2offset(data_num, ch_width); | 835 | io->buff_sample_pos += samples; |
743 | 836 | ||
744 | if (over_period) | 837 | if (over_period) |
745 | snd_pcm_period_elapsed(substream); | 838 | snd_pcm_period_elapsed(substream); |
@@ -788,16 +881,20 @@ static irqreturn_t fsi_interrupt(int irq, void *data) | |||
788 | * dai ops | 881 | * dai ops |
789 | */ | 882 | */ |
790 | 883 | ||
791 | static int fsi_dai_startup(struct snd_pcm_substream *substream, | 884 | static int fsi_hw_startup(struct fsi_priv *fsi, |
792 | struct snd_soc_dai *dai) | 885 | int is_play, |
886 | struct device *dev) | ||
793 | { | 887 | { |
794 | struct fsi_priv *fsi = fsi_get_priv(substream); | ||
795 | u32 flags = fsi_get_info_flags(fsi); | 888 | u32 flags = fsi_get_info_flags(fsi); |
796 | u32 data; | 889 | u32 data = 0; |
797 | int is_play = fsi_is_play(substream); | ||
798 | 890 | ||
799 | pm_runtime_get_sync(dai->dev); | 891 | pm_runtime_get_sync(dev); |
800 | 892 | ||
893 | /* clock setting */ | ||
894 | if (fsi_is_clk_master(fsi)) | ||
895 | data = DIMD | DOMD; | ||
896 | |||
897 | fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); | ||
801 | 898 | ||
802 | /* clock inversion (CKG2) */ | 899 | /* clock inversion (CKG2) */ |
803 | data = 0; | 900 | data = 0; |
@@ -812,54 +909,70 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
812 | 909 | ||
813 | fsi_reg_write(fsi, CKG2, data); | 910 | fsi_reg_write(fsi, CKG2, data); |
814 | 911 | ||
912 | /* set format */ | ||
913 | fsi_reg_write(fsi, DO_FMT, fsi->do_fmt); | ||
914 | fsi_reg_write(fsi, DI_FMT, fsi->di_fmt); | ||
915 | |||
916 | /* spdif ? */ | ||
917 | if (fsi_is_spdif(fsi)) { | ||
918 | fsi_spdif_clk_ctrl(fsi, 1); | ||
919 | fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); | ||
920 | } | ||
921 | |||
815 | /* irq clear */ | 922 | /* irq clear */ |
816 | fsi_irq_disable(fsi, is_play); | 923 | fsi_irq_disable(fsi, is_play); |
817 | fsi_irq_clear_status(fsi); | 924 | fsi_irq_clear_status(fsi); |
818 | 925 | ||
819 | /* fifo init */ | 926 | /* fifo init */ |
820 | fsi_fifo_init(fsi, is_play, dai); | 927 | fsi_fifo_init(fsi, is_play, dev); |
821 | 928 | ||
822 | return 0; | 929 | return 0; |
823 | } | 930 | } |
824 | 931 | ||
825 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | 932 | static void fsi_hw_shutdown(struct fsi_priv *fsi, |
826 | struct snd_soc_dai *dai) | 933 | int is_play, |
934 | struct device *dev) | ||
935 | { | ||
936 | if (fsi_is_clk_master(fsi)) | ||
937 | fsi_set_master_clk(dev, fsi, fsi->rate, 0); | ||
938 | |||
939 | pm_runtime_put_sync(dev); | ||
940 | } | ||
941 | |||
942 | static int fsi_dai_startup(struct snd_pcm_substream *substream, | ||
943 | struct snd_soc_dai *dai) | ||
827 | { | 944 | { |
828 | struct fsi_priv *fsi = fsi_get_priv(substream); | 945 | struct fsi_priv *fsi = fsi_get_priv(substream); |
829 | int is_play = fsi_is_play(substream); | 946 | int is_play = fsi_is_play(substream); |
830 | struct fsi_master *master = fsi_get_master(fsi); | ||
831 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
832 | 947 | ||
833 | fsi_irq_disable(fsi, is_play); | 948 | return fsi_hw_startup(fsi, is_play, dai->dev); |
949 | } | ||
834 | 950 | ||
835 | if (fsi_is_clk_master(fsi)) | 951 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, |
836 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); | 952 | struct snd_soc_dai *dai) |
953 | { | ||
954 | struct fsi_priv *fsi = fsi_get_priv(substream); | ||
955 | int is_play = fsi_is_play(substream); | ||
837 | 956 | ||
957 | fsi_hw_shutdown(fsi, is_play, dai->dev); | ||
838 | fsi->rate = 0; | 958 | fsi->rate = 0; |
839 | |||
840 | pm_runtime_put_sync(dai->dev); | ||
841 | } | 959 | } |
842 | 960 | ||
843 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | 961 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
844 | struct snd_soc_dai *dai) | 962 | struct snd_soc_dai *dai) |
845 | { | 963 | { |
846 | struct fsi_priv *fsi = fsi_get_priv(substream); | 964 | struct fsi_priv *fsi = fsi_get_priv(substream); |
847 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
848 | int is_play = fsi_is_play(substream); | 965 | int is_play = fsi_is_play(substream); |
849 | int ret = 0; | 966 | int ret = 0; |
850 | 967 | ||
851 | switch (cmd) { | 968 | switch (cmd) { |
852 | case SNDRV_PCM_TRIGGER_START: | 969 | case SNDRV_PCM_TRIGGER_START: |
853 | fsi_stream_push(fsi, is_play, substream, | 970 | fsi_stream_push(fsi, is_play, substream); |
854 | frames_to_bytes(runtime, runtime->buffer_size), | ||
855 | frames_to_bytes(runtime, runtime->period_size)); | ||
856 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); | 971 | ret = is_play ? fsi_data_push(fsi) : fsi_data_pop(fsi); |
857 | fsi_irq_enable(fsi, is_play); | 972 | fsi_port_start(fsi, is_play); |
858 | fsi_port_start(fsi); | ||
859 | break; | 973 | break; |
860 | case SNDRV_PCM_TRIGGER_STOP: | 974 | case SNDRV_PCM_TRIGGER_STOP: |
861 | fsi_port_stop(fsi); | 975 | fsi_port_stop(fsi, is_play); |
862 | fsi_irq_disable(fsi, is_play); | ||
863 | fsi_stream_pop(fsi, is_play); | 976 | fsi_stream_pop(fsi, is_play); |
864 | break; | 977 | break; |
865 | } | 978 | } |
@@ -884,8 +997,8 @@ static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) | |||
884 | return -EINVAL; | 997 | return -EINVAL; |
885 | } | 998 | } |
886 | 999 | ||
887 | fsi_reg_write(fsi, DO_FMT, data); | 1000 | fsi->do_fmt = data; |
888 | fsi_reg_write(fsi, DI_FMT, data); | 1001 | fsi->di_fmt = data; |
889 | 1002 | ||
890 | return 0; | 1003 | return 0; |
891 | } | 1004 | } |
@@ -900,11 +1013,10 @@ static int fsi_set_fmt_spdif(struct fsi_priv *fsi) | |||
900 | 1013 | ||
901 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; | 1014 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; |
902 | fsi->chan_num = 2; | 1015 | fsi->chan_num = 2; |
903 | fsi_spdif_clk_ctrl(fsi, 1); | 1016 | fsi->spdif = 1; |
904 | fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); | ||
905 | 1017 | ||
906 | fsi_reg_write(fsi, DO_FMT, data); | 1018 | fsi->do_fmt = data; |
907 | fsi_reg_write(fsi, DI_FMT, data); | 1019 | fsi->di_fmt = data; |
908 | 1020 | ||
909 | return 0; | 1021 | return 0; |
910 | } | 1022 | } |
@@ -915,32 +1027,24 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
915 | struct fsi_master *master = fsi_get_master(fsi); | 1027 | struct fsi_master *master = fsi_get_master(fsi); |
916 | set_rate_func set_rate = fsi_get_info_set_rate(master); | 1028 | set_rate_func set_rate = fsi_get_info_set_rate(master); |
917 | u32 flags = fsi_get_info_flags(fsi); | 1029 | u32 flags = fsi_get_info_flags(fsi); |
918 | u32 data = 0; | ||
919 | int ret; | 1030 | int ret; |
920 | 1031 | ||
921 | pm_runtime_get_sync(dai->dev); | ||
922 | |||
923 | /* set master/slave audio interface */ | 1032 | /* set master/slave audio interface */ |
924 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 1033 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
925 | case SND_SOC_DAIFMT_CBM_CFM: | 1034 | case SND_SOC_DAIFMT_CBM_CFM: |
926 | data = DIMD | DOMD; | ||
927 | fsi->clk_master = 1; | 1035 | fsi->clk_master = 1; |
928 | break; | 1036 | break; |
929 | case SND_SOC_DAIFMT_CBS_CFS: | 1037 | case SND_SOC_DAIFMT_CBS_CFS: |
930 | break; | 1038 | break; |
931 | default: | 1039 | default: |
932 | ret = -EINVAL; | 1040 | return -EINVAL; |
933 | goto set_fmt_exit; | ||
934 | } | 1041 | } |
935 | 1042 | ||
936 | if (fsi_is_clk_master(fsi) && !set_rate) { | 1043 | if (fsi_is_clk_master(fsi) && !set_rate) { |
937 | dev_err(dai->dev, "platform doesn't have set_rate\n"); | 1044 | dev_err(dai->dev, "platform doesn't have set_rate\n"); |
938 | ret = -EINVAL; | 1045 | return -EINVAL; |
939 | goto set_fmt_exit; | ||
940 | } | 1046 | } |
941 | 1047 | ||
942 | fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); | ||
943 | |||
944 | /* set format */ | 1048 | /* set format */ |
945 | switch (flags & SH_FSI_FMT_MASK) { | 1049 | switch (flags & SH_FSI_FMT_MASK) { |
946 | case SH_FSI_FMT_DAI: | 1050 | case SH_FSI_FMT_DAI: |
@@ -953,9 +1057,6 @@ static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
953 | ret = -EINVAL; | 1057 | ret = -EINVAL; |
954 | } | 1058 | } |
955 | 1059 | ||
956 | set_fmt_exit: | ||
957 | pm_runtime_put_sync(dai->dev); | ||
958 | |||
959 | return ret; | 1060 | return ret; |
960 | } | 1061 | } |
961 | 1062 | ||
@@ -964,79 +1065,19 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | |||
964 | struct snd_soc_dai *dai) | 1065 | struct snd_soc_dai *dai) |
965 | { | 1066 | { |
966 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1067 | struct fsi_priv *fsi = fsi_get_priv(substream); |
967 | struct fsi_master *master = fsi_get_master(fsi); | ||
968 | set_rate_func set_rate = fsi_get_info_set_rate(master); | ||
969 | int fsi_ver = master->core->ver; | ||
970 | long rate = params_rate(params); | 1068 | long rate = params_rate(params); |
971 | int ret; | 1069 | int ret; |
972 | 1070 | ||
973 | if (!fsi_is_clk_master(fsi)) | 1071 | if (!fsi_is_clk_master(fsi)) |
974 | return 0; | 1072 | return 0; |
975 | 1073 | ||
976 | ret = set_rate(dai->dev, fsi_is_port_a(fsi), rate, 1); | 1074 | ret = fsi_set_master_clk(dai->dev, fsi, rate, 1); |
977 | if (ret < 0) /* error */ | 1075 | if (ret < 0) |
978 | return ret; | 1076 | return ret; |
979 | 1077 | ||
980 | fsi->rate = rate; | 1078 | fsi->rate = rate; |
981 | if (ret > 0) { | ||
982 | u32 data = 0; | ||
983 | |||
984 | switch (ret & SH_FSI_ACKMD_MASK) { | ||
985 | default: | ||
986 | /* FALL THROUGH */ | ||
987 | case SH_FSI_ACKMD_512: | ||
988 | data |= (0x0 << 12); | ||
989 | break; | ||
990 | case SH_FSI_ACKMD_256: | ||
991 | data |= (0x1 << 12); | ||
992 | break; | ||
993 | case SH_FSI_ACKMD_128: | ||
994 | data |= (0x2 << 12); | ||
995 | break; | ||
996 | case SH_FSI_ACKMD_64: | ||
997 | data |= (0x3 << 12); | ||
998 | break; | ||
999 | case SH_FSI_ACKMD_32: | ||
1000 | if (fsi_ver < 2) | ||
1001 | dev_err(dai->dev, "unsupported ACKMD\n"); | ||
1002 | else | ||
1003 | data |= (0x4 << 12); | ||
1004 | break; | ||
1005 | } | ||
1006 | |||
1007 | switch (ret & SH_FSI_BPFMD_MASK) { | ||
1008 | default: | ||
1009 | /* FALL THROUGH */ | ||
1010 | case SH_FSI_BPFMD_32: | ||
1011 | data |= (0x0 << 8); | ||
1012 | break; | ||
1013 | case SH_FSI_BPFMD_64: | ||
1014 | data |= (0x1 << 8); | ||
1015 | break; | ||
1016 | case SH_FSI_BPFMD_128: | ||
1017 | data |= (0x2 << 8); | ||
1018 | break; | ||
1019 | case SH_FSI_BPFMD_256: | ||
1020 | data |= (0x3 << 8); | ||
1021 | break; | ||
1022 | case SH_FSI_BPFMD_512: | ||
1023 | data |= (0x4 << 8); | ||
1024 | break; | ||
1025 | case SH_FSI_BPFMD_16: | ||
1026 | if (fsi_ver < 2) | ||
1027 | dev_err(dai->dev, "unsupported ACKMD\n"); | ||
1028 | else | ||
1029 | data |= (0x7 << 8); | ||
1030 | break; | ||
1031 | } | ||
1032 | |||
1033 | fsi_reg_mask_set(fsi, CKG1, (ACKMD_MASK | BPFMD_MASK) , data); | ||
1034 | udelay(10); | ||
1035 | ret = 0; | ||
1036 | } | ||
1037 | 1079 | ||
1038 | return ret; | 1080 | return ret; |
1039 | |||
1040 | } | 1081 | } |
1041 | 1082 | ||
1042 | static struct snd_soc_dai_ops fsi_dai_ops = { | 1083 | static struct snd_soc_dai_ops fsi_dai_ops = { |
@@ -1097,16 +1138,14 @@ static int fsi_hw_free(struct snd_pcm_substream *substream) | |||
1097 | 1138 | ||
1098 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | 1139 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) |
1099 | { | 1140 | { |
1100 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1101 | struct fsi_priv *fsi = fsi_get_priv(substream); | 1141 | struct fsi_priv *fsi = fsi_get_priv(substream); |
1102 | struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); | 1142 | struct fsi_stream *io = fsi_get_stream(fsi, fsi_is_play(substream)); |
1103 | long location; | 1143 | int samples_pos = io->buff_sample_pos - 1; |
1104 | 1144 | ||
1105 | location = (io->buff_offset - 1); | 1145 | if (samples_pos < 0) |
1106 | if (location < 0) | 1146 | samples_pos = 0; |
1107 | location = 0; | ||
1108 | 1147 | ||
1109 | return bytes_to_frames(runtime, location); | 1148 | return fsi_sample2frame(fsi, samples_pos); |
1110 | } | 1149 | } |
1111 | 1150 | ||
1112 | static struct snd_pcm_ops fsi_pcm_ops = { | 1151 | static struct snd_pcm_ops fsi_pcm_ops = { |
@@ -1129,10 +1168,10 @@ static void fsi_pcm_free(struct snd_pcm *pcm) | |||
1129 | snd_pcm_lib_preallocate_free_for_all(pcm); | 1168 | snd_pcm_lib_preallocate_free_for_all(pcm); |
1130 | } | 1169 | } |
1131 | 1170 | ||
1132 | static int fsi_pcm_new(struct snd_card *card, | 1171 | static int fsi_pcm_new(struct snd_soc_pcm_runtime *rtd) |
1133 | struct snd_soc_dai *dai, | ||
1134 | struct snd_pcm *pcm) | ||
1135 | { | 1172 | { |
1173 | struct snd_pcm *pcm = rtd->pcm; | ||
1174 | |||
1136 | /* | 1175 | /* |
1137 | * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel | 1176 | * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel |
1138 | * in MMAP mode (i.e. aplay -M) | 1177 | * in MMAP mode (i.e. aplay -M) |
@@ -1246,8 +1285,6 @@ static int fsi_probe(struct platform_device *pdev) | |||
1246 | pm_runtime_enable(&pdev->dev); | 1285 | pm_runtime_enable(&pdev->dev); |
1247 | dev_set_drvdata(&pdev->dev, master); | 1286 | dev_set_drvdata(&pdev->dev, master); |
1248 | 1287 | ||
1249 | fsi_module_init(master, &pdev->dev); | ||
1250 | |||
1251 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, | 1288 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, |
1252 | id_entry->name, master); | 1289 | id_entry->name, master); |
1253 | if (ret) { | 1290 | if (ret) { |
@@ -1290,8 +1327,6 @@ static int fsi_remove(struct platform_device *pdev) | |||
1290 | 1327 | ||
1291 | master = dev_get_drvdata(&pdev->dev); | 1328 | master = dev_get_drvdata(&pdev->dev); |
1292 | 1329 | ||
1293 | fsi_module_kill(master, &pdev->dev); | ||
1294 | |||
1295 | free_irq(master->irq, master); | 1330 | free_irq(master->irq, master); |
1296 | pm_runtime_disable(&pdev->dev); | 1331 | pm_runtime_disable(&pdev->dev); |
1297 | 1332 | ||
@@ -1305,53 +1340,43 @@ static int fsi_remove(struct platform_device *pdev) | |||
1305 | } | 1340 | } |
1306 | 1341 | ||
1307 | static void __fsi_suspend(struct fsi_priv *fsi, | 1342 | static void __fsi_suspend(struct fsi_priv *fsi, |
1308 | struct device *dev, | 1343 | int is_play, |
1309 | set_rate_func set_rate) | 1344 | struct device *dev) |
1310 | { | 1345 | { |
1311 | fsi->saved_do_fmt = fsi_reg_read(fsi, DO_FMT); | 1346 | if (!fsi_stream_is_working(fsi, is_play)) |
1312 | fsi->saved_di_fmt = fsi_reg_read(fsi, DI_FMT); | 1347 | return; |
1313 | fsi->saved_ckg1 = fsi_reg_read(fsi, CKG1); | ||
1314 | fsi->saved_ckg2 = fsi_reg_read(fsi, CKG2); | ||
1315 | fsi->saved_out_sel = fsi_reg_read(fsi, OUT_SEL); | ||
1316 | 1348 | ||
1317 | if (fsi_is_clk_master(fsi)) | 1349 | fsi_port_stop(fsi, is_play); |
1318 | set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 0); | 1350 | fsi_hw_shutdown(fsi, is_play, dev); |
1319 | } | 1351 | } |
1320 | 1352 | ||
1321 | static void __fsi_resume(struct fsi_priv *fsi, | 1353 | static void __fsi_resume(struct fsi_priv *fsi, |
1322 | struct device *dev, | 1354 | int is_play, |
1323 | set_rate_func set_rate) | 1355 | struct device *dev) |
1324 | { | 1356 | { |
1325 | fsi_reg_write(fsi, DO_FMT, fsi->saved_do_fmt); | 1357 | if (!fsi_stream_is_working(fsi, is_play)) |
1326 | fsi_reg_write(fsi, DI_FMT, fsi->saved_di_fmt); | 1358 | return; |
1327 | fsi_reg_write(fsi, CKG1, fsi->saved_ckg1); | 1359 | |
1328 | fsi_reg_write(fsi, CKG2, fsi->saved_ckg2); | 1360 | fsi_hw_startup(fsi, is_play, dev); |
1329 | fsi_reg_write(fsi, OUT_SEL, fsi->saved_out_sel); | 1361 | |
1362 | if (fsi_is_clk_master(fsi) && fsi->rate) | ||
1363 | fsi_set_master_clk(dev, fsi, fsi->rate, 1); | ||
1364 | |||
1365 | fsi_port_start(fsi, is_play); | ||
1330 | 1366 | ||
1331 | if (fsi_is_clk_master(fsi)) | ||
1332 | set_rate(dev, fsi_is_port_a(fsi), fsi->rate, 1); | ||
1333 | } | 1367 | } |
1334 | 1368 | ||
1335 | static int fsi_suspend(struct device *dev) | 1369 | static int fsi_suspend(struct device *dev) |
1336 | { | 1370 | { |
1337 | struct fsi_master *master = dev_get_drvdata(dev); | 1371 | struct fsi_master *master = dev_get_drvdata(dev); |
1338 | set_rate_func set_rate = fsi_get_info_set_rate(master); | 1372 | struct fsi_priv *fsia = &master->fsia; |
1339 | 1373 | struct fsi_priv *fsib = &master->fsib; | |
1340 | pm_runtime_get_sync(dev); | ||
1341 | |||
1342 | __fsi_suspend(&master->fsia, dev, set_rate); | ||
1343 | __fsi_suspend(&master->fsib, dev, set_rate); | ||
1344 | 1374 | ||
1345 | master->saved_a_mclk = fsi_core_read(master, a_mclk); | 1375 | __fsi_suspend(fsia, 1, dev); |
1346 | master->saved_b_mclk = fsi_core_read(master, b_mclk); | 1376 | __fsi_suspend(fsia, 0, dev); |
1347 | master->saved_iemsk = fsi_core_read(master, iemsk); | ||
1348 | master->saved_imsk = fsi_core_read(master, imsk); | ||
1349 | master->saved_clk_rst = fsi_master_read(master, CLK_RST); | ||
1350 | master->saved_soft_rst = fsi_master_read(master, SOFT_RST); | ||
1351 | 1377 | ||
1352 | fsi_module_kill(master, dev); | 1378 | __fsi_suspend(fsib, 1, dev); |
1353 | 1379 | __fsi_suspend(fsib, 0, dev); | |
1354 | pm_runtime_put_sync(dev); | ||
1355 | 1380 | ||
1356 | return 0; | 1381 | return 0; |
1357 | } | 1382 | } |
@@ -1359,23 +1384,14 @@ static int fsi_suspend(struct device *dev) | |||
1359 | static int fsi_resume(struct device *dev) | 1384 | static int fsi_resume(struct device *dev) |
1360 | { | 1385 | { |
1361 | struct fsi_master *master = dev_get_drvdata(dev); | 1386 | struct fsi_master *master = dev_get_drvdata(dev); |
1362 | set_rate_func set_rate = fsi_get_info_set_rate(master); | 1387 | struct fsi_priv *fsia = &master->fsia; |
1363 | 1388 | struct fsi_priv *fsib = &master->fsib; | |
1364 | pm_runtime_get_sync(dev); | ||
1365 | |||
1366 | fsi_module_init(master, dev); | ||
1367 | 1389 | ||
1368 | fsi_master_mask_set(master, SOFT_RST, 0xffff, master->saved_soft_rst); | 1390 | __fsi_resume(fsia, 1, dev); |
1369 | fsi_master_mask_set(master, CLK_RST, 0xffff, master->saved_clk_rst); | 1391 | __fsi_resume(fsia, 0, dev); |
1370 | fsi_core_mask_set(master, a_mclk, 0xffff, master->saved_a_mclk); | ||
1371 | fsi_core_mask_set(master, b_mclk, 0xffff, master->saved_b_mclk); | ||
1372 | fsi_core_mask_set(master, iemsk, 0xffff, master->saved_iemsk); | ||
1373 | fsi_core_mask_set(master, imsk, 0xffff, master->saved_imsk); | ||
1374 | 1392 | ||
1375 | __fsi_resume(&master->fsia, dev, set_rate); | 1393 | __fsi_resume(fsib, 1, dev); |
1376 | __fsi_resume(&master->fsib, dev, set_rate); | 1394 | __fsi_resume(fsib, 0, dev); |
1377 | |||
1378 | pm_runtime_put_sync(dev); | ||
1379 | 1395 | ||
1380 | return 0; | 1396 | return 0; |
1381 | } | 1397 | } |
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index a423babcf145..f8f681690a71 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c | |||
@@ -527,10 +527,11 @@ static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss) | |||
527 | return bytes_to_frames(ss->runtime, ptr); | 527 | return bytes_to_frames(ss->runtime, ptr); |
528 | } | 528 | } |
529 | 529 | ||
530 | static int siu_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 530 | static int siu_pcm_new(struct snd_soc_pcm_runtime *rtd) |
531 | struct snd_pcm *pcm) | ||
532 | { | 531 | { |
533 | /* card->dev == socdev->dev, see snd_soc_new_pcms() */ | 532 | /* card->dev == socdev->dev, see snd_soc_new_pcms() */ |
533 | struct snd_card *card = rtd->card->snd_card; | ||
534 | struct snd_pcm *pcm = rtd->pcm; | ||
534 | struct siu_info *info = siu_i2s_data; | 535 | struct siu_info *info = siu_i2s_data; |
535 | struct platform_device *pdev = to_platform_device(card->dev); | 536 | struct platform_device *pdev = to_platform_device(card->dev); |
536 | int ret; | 537 | int ret; |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 039b9532b270..d9f8aded51f3 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -20,422 +20,6 @@ | |||
20 | 20 | ||
21 | #include <trace/events/asoc.h> | 21 | #include <trace/events/asoc.h> |
22 | 22 | ||
23 | #ifdef CONFIG_SPI_MASTER | ||
24 | static int do_spi_write(void *control, const char *data, int len) | ||
25 | { | ||
26 | struct spi_device *spi = control; | ||
27 | int ret; | ||
28 | |||
29 | ret = spi_write(spi, data, len); | ||
30 | if (ret < 0) | ||
31 | return ret; | ||
32 | |||
33 | return len; | ||
34 | } | ||
35 | #endif | ||
36 | |||
37 | static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, | ||
38 | unsigned int value, const void *data, int len) | ||
39 | { | ||
40 | int ret; | ||
41 | |||
42 | if (!snd_soc_codec_volatile_register(codec, reg) && | ||
43 | reg < codec->driver->reg_cache_size && | ||
44 | !codec->cache_bypass) { | ||
45 | ret = snd_soc_cache_write(codec, reg, value); | ||
46 | if (ret < 0) | ||
47 | return -1; | ||
48 | } | ||
49 | |||
50 | if (codec->cache_only) { | ||
51 | codec->cache_sync = 1; | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | ret = codec->hw_write(codec->control_data, data, len); | ||
56 | if (ret == len) | ||
57 | return 0; | ||
58 | if (ret < 0) | ||
59 | return ret; | ||
60 | else | ||
61 | return -EIO; | ||
62 | } | ||
63 | |||
64 | static unsigned int do_hw_read(struct snd_soc_codec *codec, unsigned int reg) | ||
65 | { | ||
66 | int ret; | ||
67 | unsigned int val; | ||
68 | |||
69 | if (reg >= codec->driver->reg_cache_size || | ||
70 | snd_soc_codec_volatile_register(codec, reg) || | ||
71 | codec->cache_bypass) { | ||
72 | if (codec->cache_only) | ||
73 | return -1; | ||
74 | |||
75 | BUG_ON(!codec->hw_read); | ||
76 | return codec->hw_read(codec, reg); | ||
77 | } | ||
78 | |||
79 | ret = snd_soc_cache_read(codec, reg, &val); | ||
80 | if (ret < 0) | ||
81 | return -1; | ||
82 | return val; | ||
83 | } | ||
84 | |||
85 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | ||
86 | unsigned int reg) | ||
87 | { | ||
88 | return do_hw_read(codec, reg); | ||
89 | } | ||
90 | |||
91 | static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | ||
92 | unsigned int value) | ||
93 | { | ||
94 | u16 data; | ||
95 | |||
96 | data = cpu_to_be16((reg << 12) | (value & 0xffffff)); | ||
97 | |||
98 | return do_hw_write(codec, reg, value, &data, 2); | ||
99 | } | ||
100 | |||
101 | static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, | ||
102 | unsigned int reg) | ||
103 | { | ||
104 | return do_hw_read(codec, reg); | ||
105 | } | ||
106 | |||
107 | static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | ||
108 | unsigned int value) | ||
109 | { | ||
110 | u8 data[2]; | ||
111 | |||
112 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
113 | data[1] = value & 0x00ff; | ||
114 | |||
115 | return do_hw_write(codec, reg, value, data, 2); | ||
116 | } | ||
117 | |||
118 | static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
119 | unsigned int value) | ||
120 | { | ||
121 | u8 data[2]; | ||
122 | |||
123 | reg &= 0xff; | ||
124 | data[0] = reg; | ||
125 | data[1] = value & 0xff; | ||
126 | |||
127 | return do_hw_write(codec, reg, value, data, 2); | ||
128 | } | ||
129 | |||
130 | static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | ||
131 | unsigned int reg) | ||
132 | { | ||
133 | return do_hw_read(codec, reg); | ||
134 | } | ||
135 | |||
136 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | ||
137 | unsigned int value) | ||
138 | { | ||
139 | u8 data[3]; | ||
140 | |||
141 | data[0] = reg; | ||
142 | data[1] = (value >> 8) & 0xff; | ||
143 | data[2] = value & 0xff; | ||
144 | |||
145 | return do_hw_write(codec, reg, value, data, 3); | ||
146 | } | ||
147 | |||
148 | static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | ||
149 | unsigned int reg) | ||
150 | { | ||
151 | return do_hw_read(codec, reg); | ||
152 | } | ||
153 | |||
154 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
155 | static unsigned int do_i2c_read(struct snd_soc_codec *codec, | ||
156 | void *reg, int reglen, | ||
157 | void *data, int datalen) | ||
158 | { | ||
159 | struct i2c_msg xfer[2]; | ||
160 | int ret; | ||
161 | struct i2c_client *client = codec->control_data; | ||
162 | |||
163 | /* Write register */ | ||
164 | xfer[0].addr = client->addr; | ||
165 | xfer[0].flags = 0; | ||
166 | xfer[0].len = reglen; | ||
167 | xfer[0].buf = reg; | ||
168 | |||
169 | /* Read data */ | ||
170 | xfer[1].addr = client->addr; | ||
171 | xfer[1].flags = I2C_M_RD; | ||
172 | xfer[1].len = datalen; | ||
173 | xfer[1].buf = data; | ||
174 | |||
175 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
176 | if (ret == 2) | ||
177 | return 0; | ||
178 | else if (ret < 0) | ||
179 | return ret; | ||
180 | else | ||
181 | return -EIO; | ||
182 | } | ||
183 | #endif | ||
184 | |||
185 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
186 | static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, | ||
187 | unsigned int r) | ||
188 | { | ||
189 | u8 reg = r; | ||
190 | u8 data; | ||
191 | int ret; | ||
192 | |||
193 | ret = do_i2c_read(codec, ®, 1, &data, 1); | ||
194 | if (ret < 0) | ||
195 | return 0; | ||
196 | return data; | ||
197 | } | ||
198 | #else | ||
199 | #define snd_soc_8_8_read_i2c NULL | ||
200 | #endif | ||
201 | |||
202 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
203 | static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | ||
204 | unsigned int r) | ||
205 | { | ||
206 | u8 reg = r; | ||
207 | u16 data; | ||
208 | int ret; | ||
209 | |||
210 | ret = do_i2c_read(codec, ®, 1, &data, 2); | ||
211 | if (ret < 0) | ||
212 | return 0; | ||
213 | return (data >> 8) | ((data & 0xff) << 8); | ||
214 | } | ||
215 | #else | ||
216 | #define snd_soc_8_16_read_i2c NULL | ||
217 | #endif | ||
218 | |||
219 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
220 | static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | ||
221 | unsigned int r) | ||
222 | { | ||
223 | u16 reg = r; | ||
224 | u8 data; | ||
225 | int ret; | ||
226 | |||
227 | ret = do_i2c_read(codec, ®, 2, &data, 1); | ||
228 | if (ret < 0) | ||
229 | return 0; | ||
230 | return data; | ||
231 | } | ||
232 | #else | ||
233 | #define snd_soc_16_8_read_i2c NULL | ||
234 | #endif | ||
235 | |||
236 | static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | ||
237 | unsigned int reg) | ||
238 | { | ||
239 | return do_hw_read(codec, reg); | ||
240 | } | ||
241 | |||
242 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
243 | unsigned int value) | ||
244 | { | ||
245 | u8 data[3]; | ||
246 | |||
247 | data[0] = (reg >> 8) & 0xff; | ||
248 | data[1] = reg & 0xff; | ||
249 | data[2] = value; | ||
250 | |||
251 | return do_hw_write(codec, reg, value, data, 3); | ||
252 | } | ||
253 | |||
254 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
255 | static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, | ||
256 | unsigned int r) | ||
257 | { | ||
258 | u16 reg = cpu_to_be16(r); | ||
259 | u16 data; | ||
260 | int ret; | ||
261 | |||
262 | ret = do_i2c_read(codec, ®, 2, &data, 2); | ||
263 | if (ret < 0) | ||
264 | return 0; | ||
265 | return be16_to_cpu(data); | ||
266 | } | ||
267 | #else | ||
268 | #define snd_soc_16_16_read_i2c NULL | ||
269 | #endif | ||
270 | |||
271 | static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, | ||
272 | unsigned int reg) | ||
273 | { | ||
274 | return do_hw_read(codec, reg); | ||
275 | } | ||
276 | |||
277 | static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, | ||
278 | unsigned int value) | ||
279 | { | ||
280 | u8 data[4]; | ||
281 | |||
282 | data[0] = (reg >> 8) & 0xff; | ||
283 | data[1] = reg & 0xff; | ||
284 | data[2] = (value >> 8) & 0xff; | ||
285 | data[3] = value & 0xff; | ||
286 | |||
287 | return do_hw_write(codec, reg, value, data, 4); | ||
288 | } | ||
289 | |||
290 | /* Primitive bulk write support for soc-cache. The data pointed to by | ||
291 | * `data' needs to already be in the form the hardware expects | ||
292 | * including any leading register specific data. Any data written | ||
293 | * through this function will not go through the cache as it only | ||
294 | * handles writing to volatile or out of bounds registers. | ||
295 | */ | ||
296 | static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, | ||
297 | const void *data, size_t len) | ||
298 | { | ||
299 | int ret; | ||
300 | |||
301 | /* To ensure that we don't get out of sync with the cache, check | ||
302 | * whether the base register is volatile or if we've directly asked | ||
303 | * to bypass the cache. Out of bounds registers are considered | ||
304 | * volatile. | ||
305 | */ | ||
306 | if (!codec->cache_bypass | ||
307 | && !snd_soc_codec_volatile_register(codec, reg) | ||
308 | && reg < codec->driver->reg_cache_size) | ||
309 | return -EINVAL; | ||
310 | |||
311 | switch (codec->control_type) { | ||
312 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
313 | case SND_SOC_I2C: | ||
314 | ret = i2c_master_send(codec->control_data, data, len); | ||
315 | break; | ||
316 | #endif | ||
317 | #if defined(CONFIG_SPI_MASTER) | ||
318 | case SND_SOC_SPI: | ||
319 | ret = spi_write(codec->control_data, data, len); | ||
320 | break; | ||
321 | #endif | ||
322 | default: | ||
323 | BUG(); | ||
324 | } | ||
325 | |||
326 | if (ret == len) | ||
327 | return 0; | ||
328 | if (ret < 0) | ||
329 | return ret; | ||
330 | else | ||
331 | return -EIO; | ||
332 | } | ||
333 | |||
334 | static struct { | ||
335 | int addr_bits; | ||
336 | int data_bits; | ||
337 | int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); | ||
338 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | ||
339 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | ||
340 | } io_types[] = { | ||
341 | { | ||
342 | .addr_bits = 4, .data_bits = 12, | ||
343 | .write = snd_soc_4_12_write, .read = snd_soc_4_12_read, | ||
344 | }, | ||
345 | { | ||
346 | .addr_bits = 7, .data_bits = 9, | ||
347 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, | ||
348 | }, | ||
349 | { | ||
350 | .addr_bits = 8, .data_bits = 8, | ||
351 | .write = snd_soc_8_8_write, .read = snd_soc_8_8_read, | ||
352 | .i2c_read = snd_soc_8_8_read_i2c, | ||
353 | }, | ||
354 | { | ||
355 | .addr_bits = 8, .data_bits = 16, | ||
356 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, | ||
357 | .i2c_read = snd_soc_8_16_read_i2c, | ||
358 | }, | ||
359 | { | ||
360 | .addr_bits = 16, .data_bits = 8, | ||
361 | .write = snd_soc_16_8_write, .read = snd_soc_16_8_read, | ||
362 | .i2c_read = snd_soc_16_8_read_i2c, | ||
363 | }, | ||
364 | { | ||
365 | .addr_bits = 16, .data_bits = 16, | ||
366 | .write = snd_soc_16_16_write, .read = snd_soc_16_16_read, | ||
367 | .i2c_read = snd_soc_16_16_read_i2c, | ||
368 | }, | ||
369 | }; | ||
370 | |||
371 | /** | ||
372 | * snd_soc_codec_set_cache_io: Set up standard I/O functions. | ||
373 | * | ||
374 | * @codec: CODEC to configure. | ||
375 | * @addr_bits: Number of bits of register address data. | ||
376 | * @data_bits: Number of bits of data per register. | ||
377 | * @control: Control bus used. | ||
378 | * | ||
379 | * Register formats are frequently shared between many I2C and SPI | ||
380 | * devices. In order to promote code reuse the ASoC core provides | ||
381 | * some standard implementations of CODEC read and write operations | ||
382 | * which can be set up using this function. | ||
383 | * | ||
384 | * The caller is responsible for allocating and initialising the | ||
385 | * actual cache. | ||
386 | * | ||
387 | * Note that at present this code cannot be used by CODECs with | ||
388 | * volatile registers. | ||
389 | */ | ||
390 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | ||
391 | int addr_bits, int data_bits, | ||
392 | enum snd_soc_control_type control) | ||
393 | { | ||
394 | int i; | ||
395 | |||
396 | for (i = 0; i < ARRAY_SIZE(io_types); i++) | ||
397 | if (io_types[i].addr_bits == addr_bits && | ||
398 | io_types[i].data_bits == data_bits) | ||
399 | break; | ||
400 | if (i == ARRAY_SIZE(io_types)) { | ||
401 | printk(KERN_ERR | ||
402 | "No I/O functions for %d bit address %d bit data\n", | ||
403 | addr_bits, data_bits); | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | codec->write = io_types[i].write; | ||
408 | codec->read = io_types[i].read; | ||
409 | codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; | ||
410 | |||
411 | switch (control) { | ||
412 | case SND_SOC_I2C: | ||
413 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
414 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
415 | #endif | ||
416 | if (io_types[i].i2c_read) | ||
417 | codec->hw_read = io_types[i].i2c_read; | ||
418 | |||
419 | codec->control_data = container_of(codec->dev, | ||
420 | struct i2c_client, | ||
421 | dev); | ||
422 | break; | ||
423 | |||
424 | case SND_SOC_SPI: | ||
425 | #ifdef CONFIG_SPI_MASTER | ||
426 | codec->hw_write = do_spi_write; | ||
427 | #endif | ||
428 | |||
429 | codec->control_data = container_of(codec->dev, | ||
430 | struct spi_device, | ||
431 | dev); | ||
432 | break; | ||
433 | } | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | ||
438 | |||
439 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | 23 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, |
440 | unsigned int val, unsigned int word_size) | 24 | unsigned int val, unsigned int word_size) |
441 | { | 25 | { |
@@ -483,31 +67,86 @@ static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | |||
483 | } | 67 | } |
484 | 68 | ||
485 | struct snd_soc_rbtree_node { | 69 | struct snd_soc_rbtree_node { |
486 | struct rb_node node; | 70 | struct rb_node node; /* the actual rbtree node holding this block */ |
487 | unsigned int reg; | 71 | unsigned int base_reg; /* base register handled by this block */ |
488 | unsigned int value; | 72 | unsigned int word_size; /* number of bytes needed to represent the register index */ |
489 | unsigned int defval; | 73 | void *block; /* block of adjacent registers */ |
74 | unsigned int blklen; /* number of registers available in the block */ | ||
490 | } __attribute__ ((packed)); | 75 | } __attribute__ ((packed)); |
491 | 76 | ||
492 | struct snd_soc_rbtree_ctx { | 77 | struct snd_soc_rbtree_ctx { |
493 | struct rb_root root; | 78 | struct rb_root root; |
79 | struct snd_soc_rbtree_node *cached_rbnode; | ||
494 | }; | 80 | }; |
495 | 81 | ||
82 | static inline void snd_soc_rbtree_get_base_top_reg( | ||
83 | struct snd_soc_rbtree_node *rbnode, | ||
84 | unsigned int *base, unsigned int *top) | ||
85 | { | ||
86 | *base = rbnode->base_reg; | ||
87 | *top = rbnode->base_reg + rbnode->blklen - 1; | ||
88 | } | ||
89 | |||
90 | static unsigned int snd_soc_rbtree_get_register( | ||
91 | struct snd_soc_rbtree_node *rbnode, unsigned int idx) | ||
92 | { | ||
93 | unsigned int val; | ||
94 | |||
95 | switch (rbnode->word_size) { | ||
96 | case 1: { | ||
97 | u8 *p = rbnode->block; | ||
98 | val = p[idx]; | ||
99 | return val; | ||
100 | } | ||
101 | case 2: { | ||
102 | u16 *p = rbnode->block; | ||
103 | val = p[idx]; | ||
104 | return val; | ||
105 | } | ||
106 | default: | ||
107 | BUG(); | ||
108 | break; | ||
109 | } | ||
110 | return -1; | ||
111 | } | ||
112 | |||
113 | static void snd_soc_rbtree_set_register(struct snd_soc_rbtree_node *rbnode, | ||
114 | unsigned int idx, unsigned int val) | ||
115 | { | ||
116 | switch (rbnode->word_size) { | ||
117 | case 1: { | ||
118 | u8 *p = rbnode->block; | ||
119 | p[idx] = val; | ||
120 | break; | ||
121 | } | ||
122 | case 2: { | ||
123 | u16 *p = rbnode->block; | ||
124 | p[idx] = val; | ||
125 | break; | ||
126 | } | ||
127 | default: | ||
128 | BUG(); | ||
129 | break; | ||
130 | } | ||
131 | } | ||
132 | |||
496 | static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( | 133 | static struct snd_soc_rbtree_node *snd_soc_rbtree_lookup( |
497 | struct rb_root *root, unsigned int reg) | 134 | struct rb_root *root, unsigned int reg) |
498 | { | 135 | { |
499 | struct rb_node *node; | 136 | struct rb_node *node; |
500 | struct snd_soc_rbtree_node *rbnode; | 137 | struct snd_soc_rbtree_node *rbnode; |
138 | unsigned int base_reg, top_reg; | ||
501 | 139 | ||
502 | node = root->rb_node; | 140 | node = root->rb_node; |
503 | while (node) { | 141 | while (node) { |
504 | rbnode = container_of(node, struct snd_soc_rbtree_node, node); | 142 | rbnode = container_of(node, struct snd_soc_rbtree_node, node); |
505 | if (rbnode->reg < reg) | 143 | snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); |
506 | node = node->rb_left; | 144 | if (reg >= base_reg && reg <= top_reg) |
507 | else if (rbnode->reg > reg) | ||
508 | node = node->rb_right; | ||
509 | else | ||
510 | return rbnode; | 145 | return rbnode; |
146 | else if (reg > top_reg) | ||
147 | node = node->rb_right; | ||
148 | else if (reg < base_reg) | ||
149 | node = node->rb_left; | ||
511 | } | 150 | } |
512 | 151 | ||
513 | return NULL; | 152 | return NULL; |
@@ -518,19 +157,28 @@ static int snd_soc_rbtree_insert(struct rb_root *root, | |||
518 | { | 157 | { |
519 | struct rb_node **new, *parent; | 158 | struct rb_node **new, *parent; |
520 | struct snd_soc_rbtree_node *rbnode_tmp; | 159 | struct snd_soc_rbtree_node *rbnode_tmp; |
160 | unsigned int base_reg_tmp, top_reg_tmp; | ||
161 | unsigned int base_reg; | ||
521 | 162 | ||
522 | parent = NULL; | 163 | parent = NULL; |
523 | new = &root->rb_node; | 164 | new = &root->rb_node; |
524 | while (*new) { | 165 | while (*new) { |
525 | rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, | 166 | rbnode_tmp = container_of(*new, struct snd_soc_rbtree_node, |
526 | node); | 167 | node); |
168 | /* base and top registers of the current rbnode */ | ||
169 | snd_soc_rbtree_get_base_top_reg(rbnode_tmp, &base_reg_tmp, | ||
170 | &top_reg_tmp); | ||
171 | /* base register of the rbnode to be added */ | ||
172 | base_reg = rbnode->base_reg; | ||
527 | parent = *new; | 173 | parent = *new; |
528 | if (rbnode_tmp->reg < rbnode->reg) | 174 | /* if this register has already been inserted, just return */ |
529 | new = &((*new)->rb_left); | 175 | if (base_reg >= base_reg_tmp && |
530 | else if (rbnode_tmp->reg > rbnode->reg) | 176 | base_reg <= top_reg_tmp) |
531 | new = &((*new)->rb_right); | ||
532 | else | ||
533 | return 0; | 177 | return 0; |
178 | else if (base_reg > top_reg_tmp) | ||
179 | new = &((*new)->rb_right); | ||
180 | else if (base_reg < base_reg_tmp) | ||
181 | new = &((*new)->rb_left); | ||
534 | } | 182 | } |
535 | 183 | ||
536 | /* insert the node into the rbtree */ | 184 | /* insert the node into the rbtree */ |
@@ -545,58 +193,146 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) | |||
545 | struct snd_soc_rbtree_ctx *rbtree_ctx; | 193 | struct snd_soc_rbtree_ctx *rbtree_ctx; |
546 | struct rb_node *node; | 194 | struct rb_node *node; |
547 | struct snd_soc_rbtree_node *rbnode; | 195 | struct snd_soc_rbtree_node *rbnode; |
548 | unsigned int val; | 196 | unsigned int regtmp; |
197 | unsigned int val, def; | ||
549 | int ret; | 198 | int ret; |
199 | int i; | ||
550 | 200 | ||
551 | rbtree_ctx = codec->reg_cache; | 201 | rbtree_ctx = codec->reg_cache; |
552 | for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { | 202 | for (node = rb_first(&rbtree_ctx->root); node; node = rb_next(node)) { |
553 | rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); | 203 | rbnode = rb_entry(node, struct snd_soc_rbtree_node, node); |
554 | if (rbnode->value == rbnode->defval) | 204 | for (i = 0; i < rbnode->blklen; ++i) { |
555 | continue; | 205 | regtmp = rbnode->base_reg + i; |
556 | WARN_ON(codec->writable_register && | 206 | WARN_ON(codec->writable_register && |
557 | codec->writable_register(codec, rbnode->reg)); | 207 | codec->writable_register(codec, regtmp)); |
558 | ret = snd_soc_cache_read(codec, rbnode->reg, &val); | 208 | val = snd_soc_rbtree_get_register(rbnode, i); |
559 | if (ret) | 209 | def = snd_soc_get_cache_val(codec->reg_def_copy, i, |
560 | return ret; | 210 | rbnode->word_size); |
561 | codec->cache_bypass = 1; | 211 | if (val == def) |
562 | ret = snd_soc_write(codec, rbnode->reg, val); | 212 | continue; |
563 | codec->cache_bypass = 0; | 213 | |
564 | if (ret) | 214 | codec->cache_bypass = 1; |
565 | return ret; | 215 | ret = snd_soc_write(codec, regtmp, val); |
566 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | 216 | codec->cache_bypass = 0; |
567 | rbnode->reg, val); | 217 | if (ret) |
218 | return ret; | ||
219 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | ||
220 | regtmp, val); | ||
221 | } | ||
568 | } | 222 | } |
569 | 223 | ||
570 | return 0; | 224 | return 0; |
571 | } | 225 | } |
572 | 226 | ||
227 | static int snd_soc_rbtree_insert_to_block(struct snd_soc_rbtree_node *rbnode, | ||
228 | unsigned int pos, unsigned int reg, | ||
229 | unsigned int value) | ||
230 | { | ||
231 | u8 *blk; | ||
232 | |||
233 | blk = krealloc(rbnode->block, | ||
234 | (rbnode->blklen + 1) * rbnode->word_size, GFP_KERNEL); | ||
235 | if (!blk) | ||
236 | return -ENOMEM; | ||
237 | |||
238 | /* insert the register value in the correct place in the rbnode block */ | ||
239 | memmove(blk + (pos + 1) * rbnode->word_size, | ||
240 | blk + pos * rbnode->word_size, | ||
241 | (rbnode->blklen - pos) * rbnode->word_size); | ||
242 | |||
243 | /* update the rbnode block, its size and the base register */ | ||
244 | rbnode->block = blk; | ||
245 | rbnode->blklen++; | ||
246 | if (!pos) | ||
247 | rbnode->base_reg = reg; | ||
248 | |||
249 | snd_soc_rbtree_set_register(rbnode, pos, value); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
573 | static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, | 253 | static int snd_soc_rbtree_cache_write(struct snd_soc_codec *codec, |
574 | unsigned int reg, unsigned int value) | 254 | unsigned int reg, unsigned int value) |
575 | { | 255 | { |
576 | struct snd_soc_rbtree_ctx *rbtree_ctx; | 256 | struct snd_soc_rbtree_ctx *rbtree_ctx; |
577 | struct snd_soc_rbtree_node *rbnode; | 257 | struct snd_soc_rbtree_node *rbnode, *rbnode_tmp; |
258 | struct rb_node *node; | ||
259 | unsigned int val; | ||
260 | unsigned int reg_tmp; | ||
261 | unsigned int base_reg, top_reg; | ||
262 | unsigned int pos; | ||
263 | int i; | ||
264 | int ret; | ||
578 | 265 | ||
579 | rbtree_ctx = codec->reg_cache; | 266 | rbtree_ctx = codec->reg_cache; |
267 | /* look up the required register in the cached rbnode */ | ||
268 | rbnode = rbtree_ctx->cached_rbnode; | ||
269 | if (rbnode) { | ||
270 | snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); | ||
271 | if (reg >= base_reg && reg <= top_reg) { | ||
272 | reg_tmp = reg - base_reg; | ||
273 | val = snd_soc_rbtree_get_register(rbnode, reg_tmp); | ||
274 | if (val == value) | ||
275 | return 0; | ||
276 | snd_soc_rbtree_set_register(rbnode, reg_tmp, value); | ||
277 | return 0; | ||
278 | } | ||
279 | } | ||
280 | /* if we can't locate it in the cached rbnode we'll have | ||
281 | * to traverse the rbtree looking for it. | ||
282 | */ | ||
580 | rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); | 283 | rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); |
581 | if (rbnode) { | 284 | if (rbnode) { |
582 | if (rbnode->value == value) | 285 | reg_tmp = reg - rbnode->base_reg; |
286 | val = snd_soc_rbtree_get_register(rbnode, reg_tmp); | ||
287 | if (val == value) | ||
583 | return 0; | 288 | return 0; |
584 | rbnode->value = value; | 289 | snd_soc_rbtree_set_register(rbnode, reg_tmp, value); |
290 | rbtree_ctx->cached_rbnode = rbnode; | ||
585 | } else { | 291 | } else { |
586 | /* bail out early, no need to create the rbnode yet */ | 292 | /* bail out early, no need to create the rbnode yet */ |
587 | if (!value) | 293 | if (!value) |
588 | return 0; | 294 | return 0; |
589 | /* | 295 | /* look for an adjacent register to the one we are about to add */ |
590 | * for uninitialized registers whose value is changed | 296 | for (node = rb_first(&rbtree_ctx->root); node; |
591 | * from the default zero, create an rbnode and insert | 297 | node = rb_next(node)) { |
592 | * it into the tree. | 298 | rbnode_tmp = rb_entry(node, struct snd_soc_rbtree_node, node); |
299 | for (i = 0; i < rbnode_tmp->blklen; ++i) { | ||
300 | reg_tmp = rbnode_tmp->base_reg + i; | ||
301 | if (abs(reg_tmp - reg) != 1) | ||
302 | continue; | ||
303 | /* decide where in the block to place our register */ | ||
304 | if (reg_tmp + 1 == reg) | ||
305 | pos = i + 1; | ||
306 | else | ||
307 | pos = i; | ||
308 | ret = snd_soc_rbtree_insert_to_block(rbnode_tmp, pos, | ||
309 | reg, value); | ||
310 | if (ret) | ||
311 | return ret; | ||
312 | rbtree_ctx->cached_rbnode = rbnode_tmp; | ||
313 | return 0; | ||
314 | } | ||
315 | } | ||
316 | /* we did not manage to find a place to insert it in an existing | ||
317 | * block so create a new rbnode with a single register in its block. | ||
318 | * This block will get populated further if any other adjacent | ||
319 | * registers get modified in the future. | ||
593 | */ | 320 | */ |
594 | rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); | 321 | rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL); |
595 | if (!rbnode) | 322 | if (!rbnode) |
596 | return -ENOMEM; | 323 | return -ENOMEM; |
597 | rbnode->reg = reg; | 324 | rbnode->blklen = 1; |
598 | rbnode->value = value; | 325 | rbnode->base_reg = reg; |
326 | rbnode->word_size = codec->driver->reg_word_size; | ||
327 | rbnode->block = kmalloc(rbnode->blklen * rbnode->word_size, | ||
328 | GFP_KERNEL); | ||
329 | if (!rbnode->block) { | ||
330 | kfree(rbnode); | ||
331 | return -ENOMEM; | ||
332 | } | ||
333 | snd_soc_rbtree_set_register(rbnode, 0, value); | ||
599 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); | 334 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbnode); |
335 | rbtree_ctx->cached_rbnode = rbnode; | ||
600 | } | 336 | } |
601 | 337 | ||
602 | return 0; | 338 | return 0; |
@@ -607,11 +343,28 @@ static int snd_soc_rbtree_cache_read(struct snd_soc_codec *codec, | |||
607 | { | 343 | { |
608 | struct snd_soc_rbtree_ctx *rbtree_ctx; | 344 | struct snd_soc_rbtree_ctx *rbtree_ctx; |
609 | struct snd_soc_rbtree_node *rbnode; | 345 | struct snd_soc_rbtree_node *rbnode; |
346 | unsigned int base_reg, top_reg; | ||
347 | unsigned int reg_tmp; | ||
610 | 348 | ||
611 | rbtree_ctx = codec->reg_cache; | 349 | rbtree_ctx = codec->reg_cache; |
350 | /* look up the required register in the cached rbnode */ | ||
351 | rbnode = rbtree_ctx->cached_rbnode; | ||
352 | if (rbnode) { | ||
353 | snd_soc_rbtree_get_base_top_reg(rbnode, &base_reg, &top_reg); | ||
354 | if (reg >= base_reg && reg <= top_reg) { | ||
355 | reg_tmp = reg - base_reg; | ||
356 | *value = snd_soc_rbtree_get_register(rbnode, reg_tmp); | ||
357 | return 0; | ||
358 | } | ||
359 | } | ||
360 | /* if we can't locate it in the cached rbnode we'll have | ||
361 | * to traverse the rbtree looking for it. | ||
362 | */ | ||
612 | rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); | 363 | rbnode = snd_soc_rbtree_lookup(&rbtree_ctx->root, reg); |
613 | if (rbnode) { | 364 | if (rbnode) { |
614 | *value = rbnode->value; | 365 | reg_tmp = reg - rbnode->base_reg; |
366 | *value = snd_soc_rbtree_get_register(rbnode, reg_tmp); | ||
367 | rbtree_ctx->cached_rbnode = rbnode; | ||
615 | } else { | 368 | } else { |
616 | /* uninitialized registers default to 0 */ | 369 | /* uninitialized registers default to 0 */ |
617 | *value = 0; | 370 | *value = 0; |
@@ -637,6 +390,7 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec) | |||
637 | rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); | 390 | rbtree_node = rb_entry(next, struct snd_soc_rbtree_node, node); |
638 | next = rb_next(&rbtree_node->node); | 391 | next = rb_next(&rbtree_node->node); |
639 | rb_erase(&rbtree_node->node, &rbtree_ctx->root); | 392 | rb_erase(&rbtree_node->node, &rbtree_ctx->root); |
393 | kfree(rbtree_node->block); | ||
640 | kfree(rbtree_node); | 394 | kfree(rbtree_node); |
641 | } | 395 | } |
642 | 396 | ||
@@ -649,10 +403,9 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec) | |||
649 | 403 | ||
650 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | 404 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) |
651 | { | 405 | { |
652 | struct snd_soc_rbtree_node *rbtree_node; | ||
653 | struct snd_soc_rbtree_ctx *rbtree_ctx; | 406 | struct snd_soc_rbtree_ctx *rbtree_ctx; |
654 | unsigned int val; | ||
655 | unsigned int word_size; | 407 | unsigned int word_size; |
408 | unsigned int val; | ||
656 | int i; | 409 | int i; |
657 | int ret; | 410 | int ret; |
658 | 411 | ||
@@ -662,32 +415,27 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | |||
662 | 415 | ||
663 | rbtree_ctx = codec->reg_cache; | 416 | rbtree_ctx = codec->reg_cache; |
664 | rbtree_ctx->root = RB_ROOT; | 417 | rbtree_ctx->root = RB_ROOT; |
418 | rbtree_ctx->cached_rbnode = NULL; | ||
665 | 419 | ||
666 | if (!codec->reg_def_copy) | 420 | if (!codec->reg_def_copy) |
667 | return 0; | 421 | return 0; |
668 | 422 | ||
669 | /* | ||
670 | * populate the rbtree with the initialized registers. All other | ||
671 | * registers will be inserted when they are first modified. | ||
672 | */ | ||
673 | word_size = codec->driver->reg_word_size; | 423 | word_size = codec->driver->reg_word_size; |
674 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { | 424 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { |
675 | val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); | 425 | val = snd_soc_get_cache_val(codec->reg_def_copy, i, |
426 | word_size); | ||
676 | if (!val) | 427 | if (!val) |
677 | continue; | 428 | continue; |
678 | rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); | 429 | ret = snd_soc_rbtree_cache_write(codec, i, val); |
679 | if (!rbtree_node) { | 430 | if (ret) |
680 | ret = -ENOMEM; | 431 | goto err; |
681 | snd_soc_cache_exit(codec); | ||
682 | break; | ||
683 | } | ||
684 | rbtree_node->reg = i; | ||
685 | rbtree_node->value = val; | ||
686 | rbtree_node->defval = val; | ||
687 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node); | ||
688 | } | 432 | } |
689 | 433 | ||
690 | return 0; | 434 | return 0; |
435 | |||
436 | err: | ||
437 | snd_soc_cache_exit(codec); | ||
438 | return ret; | ||
691 | } | 439 | } |
692 | 440 | ||
693 | #ifdef CONFIG_SND_SOC_CACHE_LZO | 441 | #ifdef CONFIG_SND_SOC_CACHE_LZO |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b194be09e74d..e44267f66216 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -44,7 +44,6 @@ | |||
44 | 44 | ||
45 | #define NAME_SIZE 32 | 45 | #define NAME_SIZE 32 |
46 | 46 | ||
47 | static DEFINE_MUTEX(pcm_mutex); | ||
48 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | 47 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); |
49 | 48 | ||
50 | #ifdef CONFIG_DEBUG_FS | 49 | #ifdef CONFIG_DEBUG_FS |
@@ -58,7 +57,7 @@ static LIST_HEAD(dai_list); | |||
58 | static LIST_HEAD(platform_list); | 57 | static LIST_HEAD(platform_list); |
59 | static LIST_HEAD(codec_list); | 58 | static LIST_HEAD(codec_list); |
60 | 59 | ||
61 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); | 60 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); |
62 | 61 | ||
63 | /* | 62 | /* |
64 | * This is a timeout to do a DAPM powerdown after a stream is closed(). | 63 | * This is a timeout to do a DAPM powerdown after a stream is closed(). |
@@ -485,552 +484,6 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) | |||
485 | } | 484 | } |
486 | #endif | 485 | #endif |
487 | 486 | ||
488 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) | ||
489 | { | ||
490 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
491 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
492 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
493 | int ret; | ||
494 | |||
495 | if (!codec_dai->driver->symmetric_rates && | ||
496 | !cpu_dai->driver->symmetric_rates && | ||
497 | !rtd->dai_link->symmetric_rates) | ||
498 | return 0; | ||
499 | |||
500 | /* This can happen if multiple streams are starting simultaneously - | ||
501 | * the second can need to get its constraints before the first has | ||
502 | * picked a rate. Complain and allow the application to carry on. | ||
503 | */ | ||
504 | if (!rtd->rate) { | ||
505 | dev_warn(&rtd->dev, | ||
506 | "Not enforcing symmetric_rates due to race\n"); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate); | ||
511 | |||
512 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, | ||
513 | SNDRV_PCM_HW_PARAM_RATE, | ||
514 | rtd->rate, rtd->rate); | ||
515 | if (ret < 0) { | ||
516 | dev_err(&rtd->dev, | ||
517 | "Unable to apply rate symmetry constraint: %d\n", ret); | ||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | /* | ||
525 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | ||
526 | * then initialized and any private data can be allocated. This also calls | ||
527 | * startup for the cpu DAI, platform, machine and codec DAI. | ||
528 | */ | ||
529 | static int soc_pcm_open(struct snd_pcm_substream *substream) | ||
530 | { | ||
531 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
532 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
533 | struct snd_soc_platform *platform = rtd->platform; | ||
534 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
535 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
536 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | ||
537 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | ||
538 | int ret = 0; | ||
539 | |||
540 | mutex_lock(&pcm_mutex); | ||
541 | |||
542 | /* startup the audio subsystem */ | ||
543 | if (cpu_dai->driver->ops->startup) { | ||
544 | ret = cpu_dai->driver->ops->startup(substream, cpu_dai); | ||
545 | if (ret < 0) { | ||
546 | printk(KERN_ERR "asoc: can't open interface %s\n", | ||
547 | cpu_dai->name); | ||
548 | goto out; | ||
549 | } | ||
550 | } | ||
551 | |||
552 | if (platform->driver->ops && platform->driver->ops->open) { | ||
553 | ret = platform->driver->ops->open(substream); | ||
554 | if (ret < 0) { | ||
555 | printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); | ||
556 | goto platform_err; | ||
557 | } | ||
558 | } | ||
559 | |||
560 | if (codec_dai->driver->ops->startup) { | ||
561 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | ||
562 | if (ret < 0) { | ||
563 | printk(KERN_ERR "asoc: can't open codec %s\n", | ||
564 | codec_dai->name); | ||
565 | goto codec_dai_err; | ||
566 | } | ||
567 | } | ||
568 | |||
569 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | ||
570 | ret = rtd->dai_link->ops->startup(substream); | ||
571 | if (ret < 0) { | ||
572 | printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); | ||
573 | goto machine_err; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | /* Check that the codec and cpu DAIs are compatible */ | ||
578 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
579 | runtime->hw.rate_min = | ||
580 | max(codec_dai_drv->playback.rate_min, | ||
581 | cpu_dai_drv->playback.rate_min); | ||
582 | runtime->hw.rate_max = | ||
583 | min(codec_dai_drv->playback.rate_max, | ||
584 | cpu_dai_drv->playback.rate_max); | ||
585 | runtime->hw.channels_min = | ||
586 | max(codec_dai_drv->playback.channels_min, | ||
587 | cpu_dai_drv->playback.channels_min); | ||
588 | runtime->hw.channels_max = | ||
589 | min(codec_dai_drv->playback.channels_max, | ||
590 | cpu_dai_drv->playback.channels_max); | ||
591 | runtime->hw.formats = | ||
592 | codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats; | ||
593 | runtime->hw.rates = | ||
594 | codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates; | ||
595 | if (codec_dai_drv->playback.rates | ||
596 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
597 | runtime->hw.rates |= cpu_dai_drv->playback.rates; | ||
598 | if (cpu_dai_drv->playback.rates | ||
599 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
600 | runtime->hw.rates |= codec_dai_drv->playback.rates; | ||
601 | } else { | ||
602 | runtime->hw.rate_min = | ||
603 | max(codec_dai_drv->capture.rate_min, | ||
604 | cpu_dai_drv->capture.rate_min); | ||
605 | runtime->hw.rate_max = | ||
606 | min(codec_dai_drv->capture.rate_max, | ||
607 | cpu_dai_drv->capture.rate_max); | ||
608 | runtime->hw.channels_min = | ||
609 | max(codec_dai_drv->capture.channels_min, | ||
610 | cpu_dai_drv->capture.channels_min); | ||
611 | runtime->hw.channels_max = | ||
612 | min(codec_dai_drv->capture.channels_max, | ||
613 | cpu_dai_drv->capture.channels_max); | ||
614 | runtime->hw.formats = | ||
615 | codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats; | ||
616 | runtime->hw.rates = | ||
617 | codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates; | ||
618 | if (codec_dai_drv->capture.rates | ||
619 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
620 | runtime->hw.rates |= cpu_dai_drv->capture.rates; | ||
621 | if (cpu_dai_drv->capture.rates | ||
622 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
623 | runtime->hw.rates |= codec_dai_drv->capture.rates; | ||
624 | } | ||
625 | |||
626 | ret = -EINVAL; | ||
627 | snd_pcm_limit_hw_rates(runtime); | ||
628 | if (!runtime->hw.rates) { | ||
629 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | ||
630 | codec_dai->name, cpu_dai->name); | ||
631 | goto config_err; | ||
632 | } | ||
633 | if (!runtime->hw.formats) { | ||
634 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | ||
635 | codec_dai->name, cpu_dai->name); | ||
636 | goto config_err; | ||
637 | } | ||
638 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || | ||
639 | runtime->hw.channels_min > runtime->hw.channels_max) { | ||
640 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | ||
641 | codec_dai->name, cpu_dai->name); | ||
642 | goto config_err; | ||
643 | } | ||
644 | |||
645 | /* Symmetry only applies if we've already got an active stream. */ | ||
646 | if (cpu_dai->active || codec_dai->active) { | ||
647 | ret = soc_pcm_apply_symmetry(substream); | ||
648 | if (ret != 0) | ||
649 | goto config_err; | ||
650 | } | ||
651 | |||
652 | pr_debug("asoc: %s <-> %s info:\n", | ||
653 | codec_dai->name, cpu_dai->name); | ||
654 | pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); | ||
655 | pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | ||
656 | runtime->hw.channels_max); | ||
657 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | ||
658 | runtime->hw.rate_max); | ||
659 | |||
660 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
661 | cpu_dai->playback_active++; | ||
662 | codec_dai->playback_active++; | ||
663 | } else { | ||
664 | cpu_dai->capture_active++; | ||
665 | codec_dai->capture_active++; | ||
666 | } | ||
667 | cpu_dai->active++; | ||
668 | codec_dai->active++; | ||
669 | rtd->codec->active++; | ||
670 | mutex_unlock(&pcm_mutex); | ||
671 | return 0; | ||
672 | |||
673 | config_err: | ||
674 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | ||
675 | rtd->dai_link->ops->shutdown(substream); | ||
676 | |||
677 | machine_err: | ||
678 | if (codec_dai->driver->ops->shutdown) | ||
679 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
680 | |||
681 | codec_dai_err: | ||
682 | if (platform->driver->ops && platform->driver->ops->close) | ||
683 | platform->driver->ops->close(substream); | ||
684 | |||
685 | platform_err: | ||
686 | if (cpu_dai->driver->ops->shutdown) | ||
687 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | ||
688 | out: | ||
689 | mutex_unlock(&pcm_mutex); | ||
690 | return ret; | ||
691 | } | ||
692 | |||
693 | /* | ||
694 | * Power down the audio subsystem pmdown_time msecs after close is called. | ||
695 | * This is to ensure there are no pops or clicks in between any music tracks | ||
696 | * due to DAPM power cycling. | ||
697 | */ | ||
698 | static void close_delayed_work(struct work_struct *work) | ||
699 | { | ||
700 | struct snd_soc_pcm_runtime *rtd = | ||
701 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | ||
702 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
703 | |||
704 | mutex_lock(&pcm_mutex); | ||
705 | |||
706 | pr_debug("pop wq checking: %s status: %s waiting: %s\n", | ||
707 | codec_dai->driver->playback.stream_name, | ||
708 | codec_dai->playback_active ? "active" : "inactive", | ||
709 | codec_dai->pop_wait ? "yes" : "no"); | ||
710 | |||
711 | /* are we waiting on this codec DAI stream */ | ||
712 | if (codec_dai->pop_wait == 1) { | ||
713 | codec_dai->pop_wait = 0; | ||
714 | snd_soc_dapm_stream_event(rtd, | ||
715 | codec_dai->driver->playback.stream_name, | ||
716 | SND_SOC_DAPM_STREAM_STOP); | ||
717 | } | ||
718 | |||
719 | mutex_unlock(&pcm_mutex); | ||
720 | } | ||
721 | |||
722 | /* | ||
723 | * Called by ALSA when a PCM substream is closed. Private data can be | ||
724 | * freed here. The cpu DAI, codec DAI, machine and platform are also | ||
725 | * shutdown. | ||
726 | */ | ||
727 | static int soc_codec_close(struct snd_pcm_substream *substream) | ||
728 | { | ||
729 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
730 | struct snd_soc_platform *platform = rtd->platform; | ||
731 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
732 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
733 | struct snd_soc_codec *codec = rtd->codec; | ||
734 | |||
735 | mutex_lock(&pcm_mutex); | ||
736 | |||
737 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
738 | cpu_dai->playback_active--; | ||
739 | codec_dai->playback_active--; | ||
740 | } else { | ||
741 | cpu_dai->capture_active--; | ||
742 | codec_dai->capture_active--; | ||
743 | } | ||
744 | |||
745 | cpu_dai->active--; | ||
746 | codec_dai->active--; | ||
747 | codec->active--; | ||
748 | |||
749 | /* Muting the DAC suppresses artifacts caused during digital | ||
750 | * shutdown, for example from stopping clocks. | ||
751 | */ | ||
752 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
753 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
754 | |||
755 | if (cpu_dai->driver->ops->shutdown) | ||
756 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | ||
757 | |||
758 | if (codec_dai->driver->ops->shutdown) | ||
759 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
760 | |||
761 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | ||
762 | rtd->dai_link->ops->shutdown(substream); | ||
763 | |||
764 | if (platform->driver->ops && platform->driver->ops->close) | ||
765 | platform->driver->ops->close(substream); | ||
766 | cpu_dai->runtime = NULL; | ||
767 | |||
768 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
769 | /* start delayed pop wq here for playback streams */ | ||
770 | codec_dai->pop_wait = 1; | ||
771 | schedule_delayed_work(&rtd->delayed_work, | ||
772 | msecs_to_jiffies(rtd->pmdown_time)); | ||
773 | } else { | ||
774 | /* capture streams can be powered down now */ | ||
775 | snd_soc_dapm_stream_event(rtd, | ||
776 | codec_dai->driver->capture.stream_name, | ||
777 | SND_SOC_DAPM_STREAM_STOP); | ||
778 | } | ||
779 | |||
780 | mutex_unlock(&pcm_mutex); | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | /* | ||
785 | * Called by ALSA when the PCM substream is prepared, can set format, sample | ||
786 | * rate, etc. This function is non atomic and can be called multiple times, | ||
787 | * it can refer to the runtime info. | ||
788 | */ | ||
789 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) | ||
790 | { | ||
791 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
792 | struct snd_soc_platform *platform = rtd->platform; | ||
793 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
794 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
795 | int ret = 0; | ||
796 | |||
797 | mutex_lock(&pcm_mutex); | ||
798 | |||
799 | if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { | ||
800 | ret = rtd->dai_link->ops->prepare(substream); | ||
801 | if (ret < 0) { | ||
802 | printk(KERN_ERR "asoc: machine prepare error\n"); | ||
803 | goto out; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | if (platform->driver->ops && platform->driver->ops->prepare) { | ||
808 | ret = platform->driver->ops->prepare(substream); | ||
809 | if (ret < 0) { | ||
810 | printk(KERN_ERR "asoc: platform prepare error\n"); | ||
811 | goto out; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | if (codec_dai->driver->ops->prepare) { | ||
816 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | ||
817 | if (ret < 0) { | ||
818 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | ||
819 | goto out; | ||
820 | } | ||
821 | } | ||
822 | |||
823 | if (cpu_dai->driver->ops->prepare) { | ||
824 | ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); | ||
825 | if (ret < 0) { | ||
826 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); | ||
827 | goto out; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | /* cancel any delayed stream shutdown that is pending */ | ||
832 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
833 | codec_dai->pop_wait) { | ||
834 | codec_dai->pop_wait = 0; | ||
835 | cancel_delayed_work(&rtd->delayed_work); | ||
836 | } | ||
837 | |||
838 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
839 | snd_soc_dapm_stream_event(rtd, | ||
840 | codec_dai->driver->playback.stream_name, | ||
841 | SND_SOC_DAPM_STREAM_START); | ||
842 | else | ||
843 | snd_soc_dapm_stream_event(rtd, | ||
844 | codec_dai->driver->capture.stream_name, | ||
845 | SND_SOC_DAPM_STREAM_START); | ||
846 | |||
847 | snd_soc_dai_digital_mute(codec_dai, 0); | ||
848 | |||
849 | out: | ||
850 | mutex_unlock(&pcm_mutex); | ||
851 | return ret; | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * Called by ALSA when the hardware params are set by application. This | ||
856 | * function can also be called multiple times and can allocate buffers | ||
857 | * (using snd_pcm_lib_* ). It's non-atomic. | ||
858 | */ | ||
859 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | ||
860 | struct snd_pcm_hw_params *params) | ||
861 | { | ||
862 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
863 | struct snd_soc_platform *platform = rtd->platform; | ||
864 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
865 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
866 | int ret = 0; | ||
867 | |||
868 | mutex_lock(&pcm_mutex); | ||
869 | |||
870 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { | ||
871 | ret = rtd->dai_link->ops->hw_params(substream, params); | ||
872 | if (ret < 0) { | ||
873 | printk(KERN_ERR "asoc: machine hw_params failed\n"); | ||
874 | goto out; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | if (codec_dai->driver->ops->hw_params) { | ||
879 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | ||
880 | if (ret < 0) { | ||
881 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | ||
882 | codec_dai->name); | ||
883 | goto codec_err; | ||
884 | } | ||
885 | } | ||
886 | |||
887 | if (cpu_dai->driver->ops->hw_params) { | ||
888 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); | ||
889 | if (ret < 0) { | ||
890 | printk(KERN_ERR "asoc: interface %s hw params failed\n", | ||
891 | cpu_dai->name); | ||
892 | goto interface_err; | ||
893 | } | ||
894 | } | ||
895 | |||
896 | if (platform->driver->ops && platform->driver->ops->hw_params) { | ||
897 | ret = platform->driver->ops->hw_params(substream, params); | ||
898 | if (ret < 0) { | ||
899 | printk(KERN_ERR "asoc: platform %s hw params failed\n", | ||
900 | platform->name); | ||
901 | goto platform_err; | ||
902 | } | ||
903 | } | ||
904 | |||
905 | rtd->rate = params_rate(params); | ||
906 | |||
907 | out: | ||
908 | mutex_unlock(&pcm_mutex); | ||
909 | return ret; | ||
910 | |||
911 | platform_err: | ||
912 | if (cpu_dai->driver->ops->hw_free) | ||
913 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | ||
914 | |||
915 | interface_err: | ||
916 | if (codec_dai->driver->ops->hw_free) | ||
917 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
918 | |||
919 | codec_err: | ||
920 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | ||
921 | rtd->dai_link->ops->hw_free(substream); | ||
922 | |||
923 | mutex_unlock(&pcm_mutex); | ||
924 | return ret; | ||
925 | } | ||
926 | |||
927 | /* | ||
928 | * Frees resources allocated by hw_params, can be called multiple times | ||
929 | */ | ||
930 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | ||
931 | { | ||
932 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
933 | struct snd_soc_platform *platform = rtd->platform; | ||
934 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
935 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
936 | struct snd_soc_codec *codec = rtd->codec; | ||
937 | |||
938 | mutex_lock(&pcm_mutex); | ||
939 | |||
940 | /* apply codec digital mute */ | ||
941 | if (!codec->active) | ||
942 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
943 | |||
944 | /* free any machine hw params */ | ||
945 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | ||
946 | rtd->dai_link->ops->hw_free(substream); | ||
947 | |||
948 | /* free any DMA resources */ | ||
949 | if (platform->driver->ops && platform->driver->ops->hw_free) | ||
950 | platform->driver->ops->hw_free(substream); | ||
951 | |||
952 | /* now free hw params for the DAIs */ | ||
953 | if (codec_dai->driver->ops->hw_free) | ||
954 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
955 | |||
956 | if (cpu_dai->driver->ops->hw_free) | ||
957 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | ||
958 | |||
959 | mutex_unlock(&pcm_mutex); | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
964 | { | ||
965 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
966 | struct snd_soc_platform *platform = rtd->platform; | ||
967 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
968 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
969 | int ret; | ||
970 | |||
971 | if (codec_dai->driver->ops->trigger) { | ||
972 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | ||
973 | if (ret < 0) | ||
974 | return ret; | ||
975 | } | ||
976 | |||
977 | if (platform->driver->ops && platform->driver->ops->trigger) { | ||
978 | ret = platform->driver->ops->trigger(substream, cmd); | ||
979 | if (ret < 0) | ||
980 | return ret; | ||
981 | } | ||
982 | |||
983 | if (cpu_dai->driver->ops->trigger) { | ||
984 | ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); | ||
985 | if (ret < 0) | ||
986 | return ret; | ||
987 | } | ||
988 | return 0; | ||
989 | } | ||
990 | |||
991 | /* | ||
992 | * soc level wrapper for pointer callback | ||
993 | * If cpu_dai, codec_dai, platform driver has the delay callback, than | ||
994 | * the runtime->delay will be updated accordingly. | ||
995 | */ | ||
996 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | ||
997 | { | ||
998 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
999 | struct snd_soc_platform *platform = rtd->platform; | ||
1000 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
1001 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1002 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1003 | snd_pcm_uframes_t offset = 0; | ||
1004 | snd_pcm_sframes_t delay = 0; | ||
1005 | |||
1006 | if (platform->driver->ops && platform->driver->ops->pointer) | ||
1007 | offset = platform->driver->ops->pointer(substream); | ||
1008 | |||
1009 | if (cpu_dai->driver->ops->delay) | ||
1010 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | ||
1011 | |||
1012 | if (codec_dai->driver->ops->delay) | ||
1013 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | ||
1014 | |||
1015 | if (platform->driver->delay) | ||
1016 | delay += platform->driver->delay(substream, codec_dai); | ||
1017 | |||
1018 | runtime->delay = delay; | ||
1019 | |||
1020 | return offset; | ||
1021 | } | ||
1022 | |||
1023 | /* ASoC PCM operations */ | ||
1024 | static struct snd_pcm_ops soc_pcm_ops = { | ||
1025 | .open = soc_pcm_open, | ||
1026 | .close = soc_codec_close, | ||
1027 | .hw_params = soc_pcm_hw_params, | ||
1028 | .hw_free = soc_pcm_hw_free, | ||
1029 | .prepare = soc_pcm_prepare, | ||
1030 | .trigger = soc_pcm_trigger, | ||
1031 | .pointer = soc_pcm_pointer, | ||
1032 | }; | ||
1033 | |||
1034 | #ifdef CONFIG_PM_SLEEP | 487 | #ifdef CONFIG_PM_SLEEP |
1035 | /* powers down audio subsystem for suspend */ | 488 | /* powers down audio subsystem for suspend */ |
1036 | int snd_soc_suspend(struct device *dev) | 489 | int snd_soc_suspend(struct device *dev) |
@@ -1256,7 +709,7 @@ static void soc_resume_deferred(struct work_struct *work) | |||
1256 | int snd_soc_resume(struct device *dev) | 709 | int snd_soc_resume(struct device *dev) |
1257 | { | 710 | { |
1258 | struct snd_soc_card *card = dev_get_drvdata(dev); | 711 | struct snd_soc_card *card = dev_get_drvdata(dev); |
1259 | int i; | 712 | int i, ac97_control = 0; |
1260 | 713 | ||
1261 | /* AC97 devices might have other drivers hanging off them so | 714 | /* AC97 devices might have other drivers hanging off them so |
1262 | * need to resume immediately. Other drivers don't have that | 715 | * need to resume immediately. Other drivers don't have that |
@@ -1265,14 +718,15 @@ int snd_soc_resume(struct device *dev) | |||
1265 | */ | 718 | */ |
1266 | for (i = 0; i < card->num_rtd; i++) { | 719 | for (i = 0; i < card->num_rtd; i++) { |
1267 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 720 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
1268 | if (cpu_dai->driver->ac97_control) { | 721 | ac97_control |= cpu_dai->driver->ac97_control; |
1269 | dev_dbg(dev, "Resuming AC97 immediately\n"); | 722 | } |
1270 | soc_resume_deferred(&card->deferred_resume_work); | 723 | if (ac97_control) { |
1271 | } else { | 724 | dev_dbg(dev, "Resuming AC97 immediately\n"); |
1272 | dev_dbg(dev, "Scheduling resume work\n"); | 725 | soc_resume_deferred(&card->deferred_resume_work); |
1273 | if (!schedule_work(&card->deferred_resume_work)) | 726 | } else { |
1274 | dev_err(dev, "resume work item may be lost\n"); | 727 | dev_dbg(dev, "Scheduling resume work\n"); |
1275 | } | 728 | if (!schedule_work(&card->deferred_resume_work)) |
729 | dev_err(dev, "resume work item may be lost\n"); | ||
1276 | } | 730 | } |
1277 | 731 | ||
1278 | return 0; | 732 | return 0; |
@@ -1393,7 +847,7 @@ static void soc_remove_codec(struct snd_soc_codec *codec) | |||
1393 | module_put(codec->dev->driver->owner); | 847 | module_put(codec->dev->driver->owner); |
1394 | } | 848 | } |
1395 | 849 | ||
1396 | static void soc_remove_dai_link(struct snd_soc_card *card, int num) | 850 | static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) |
1397 | { | 851 | { |
1398 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 852 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1399 | struct snd_soc_codec *codec = rtd->codec; | 853 | struct snd_soc_codec *codec = rtd->codec; |
@@ -1410,7 +864,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) | |||
1410 | } | 864 | } |
1411 | 865 | ||
1412 | /* remove the CODEC DAI */ | 866 | /* remove the CODEC DAI */ |
1413 | if (codec_dai && codec_dai->probed) { | 867 | if (codec_dai && codec_dai->probed && |
868 | codec_dai->driver->remove_order == order) { | ||
1414 | if (codec_dai->driver->remove) { | 869 | if (codec_dai->driver->remove) { |
1415 | err = codec_dai->driver->remove(codec_dai); | 870 | err = codec_dai->driver->remove(codec_dai); |
1416 | if (err < 0) | 871 | if (err < 0) |
@@ -1421,7 +876,8 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) | |||
1421 | } | 876 | } |
1422 | 877 | ||
1423 | /* remove the platform */ | 878 | /* remove the platform */ |
1424 | if (platform && platform->probed) { | 879 | if (platform && platform->probed && |
880 | platform->driver->remove_order == order) { | ||
1425 | if (platform->driver->remove) { | 881 | if (platform->driver->remove) { |
1426 | err = platform->driver->remove(platform); | 882 | err = platform->driver->remove(platform); |
1427 | if (err < 0) | 883 | if (err < 0) |
@@ -1433,11 +889,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) | |||
1433 | } | 889 | } |
1434 | 890 | ||
1435 | /* remove the CODEC */ | 891 | /* remove the CODEC */ |
1436 | if (codec && codec->probed) | 892 | if (codec && codec->probed && |
893 | codec->driver->remove_order == order) | ||
1437 | soc_remove_codec(codec); | 894 | soc_remove_codec(codec); |
1438 | 895 | ||
1439 | /* remove the cpu_dai */ | 896 | /* remove the cpu_dai */ |
1440 | if (cpu_dai && cpu_dai->probed) { | 897 | if (cpu_dai && cpu_dai->probed && |
898 | cpu_dai->driver->remove_order == order) { | ||
1441 | if (cpu_dai->driver->remove) { | 899 | if (cpu_dai->driver->remove) { |
1442 | err = cpu_dai->driver->remove(cpu_dai); | 900 | err = cpu_dai->driver->remove(cpu_dai); |
1443 | if (err < 0) | 901 | if (err < 0) |
@@ -1451,11 +909,13 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num) | |||
1451 | 909 | ||
1452 | static void soc_remove_dai_links(struct snd_soc_card *card) | 910 | static void soc_remove_dai_links(struct snd_soc_card *card) |
1453 | { | 911 | { |
1454 | int i; | 912 | int dai, order; |
1455 | |||
1456 | for (i = 0; i < card->num_rtd; i++) | ||
1457 | soc_remove_dai_link(card, i); | ||
1458 | 913 | ||
914 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | ||
915 | order++) { | ||
916 | for (dai = 0; dai < card->num_rtd; dai++) | ||
917 | soc_remove_dai_link(card, dai, order); | ||
918 | } | ||
1459 | card->num_rtd = 0; | 919 | card->num_rtd = 0; |
1460 | } | 920 | } |
1461 | 921 | ||
@@ -1526,6 +986,52 @@ err_probe: | |||
1526 | return ret; | 986 | return ret; |
1527 | } | 987 | } |
1528 | 988 | ||
989 | static int soc_probe_platform(struct snd_soc_card *card, | ||
990 | struct snd_soc_platform *platform) | ||
991 | { | ||
992 | int ret = 0; | ||
993 | const struct snd_soc_platform_driver *driver = platform->driver; | ||
994 | |||
995 | platform->card = card; | ||
996 | platform->dapm.card = card; | ||
997 | |||
998 | if (!try_module_get(platform->dev->driver->owner)) | ||
999 | return -ENODEV; | ||
1000 | |||
1001 | if (driver->dapm_widgets) | ||
1002 | snd_soc_dapm_new_controls(&platform->dapm, | ||
1003 | driver->dapm_widgets, driver->num_dapm_widgets); | ||
1004 | |||
1005 | if (driver->probe) { | ||
1006 | ret = driver->probe(platform); | ||
1007 | if (ret < 0) { | ||
1008 | dev_err(platform->dev, | ||
1009 | "asoc: failed to probe platform %s: %d\n", | ||
1010 | platform->name, ret); | ||
1011 | goto err_probe; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | if (driver->controls) | ||
1016 | snd_soc_add_platform_controls(platform, driver->controls, | ||
1017 | driver->num_controls); | ||
1018 | if (driver->dapm_routes) | ||
1019 | snd_soc_dapm_add_routes(&platform->dapm, driver->dapm_routes, | ||
1020 | driver->num_dapm_routes); | ||
1021 | |||
1022 | /* mark platform as probed and add to card platform list */ | ||
1023 | platform->probed = 1; | ||
1024 | list_add(&platform->card_list, &card->platform_dev_list); | ||
1025 | list_add(&platform->dapm.list, &card->dapm_list); | ||
1026 | |||
1027 | return 0; | ||
1028 | |||
1029 | err_probe: | ||
1030 | module_put(platform->dev->driver->owner); | ||
1031 | |||
1032 | return ret; | ||
1033 | } | ||
1034 | |||
1529 | static void rtd_release(struct device *dev) {} | 1035 | static void rtd_release(struct device *dev) {} |
1530 | 1036 | ||
1531 | static int soc_post_component_init(struct snd_soc_card *card, | 1037 | static int soc_post_component_init(struct snd_soc_card *card, |
@@ -1572,6 +1078,7 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1572 | rtd->dev.parent = card->dev; | 1078 | rtd->dev.parent = card->dev; |
1573 | rtd->dev.release = rtd_release; | 1079 | rtd->dev.release = rtd_release; |
1574 | rtd->dev.init_name = name; | 1080 | rtd->dev.init_name = name; |
1081 | mutex_init(&rtd->pcm_mutex); | ||
1575 | ret = device_register(&rtd->dev); | 1082 | ret = device_register(&rtd->dev); |
1576 | if (ret < 0) { | 1083 | if (ret < 0) { |
1577 | dev_err(card->dev, | 1084 | dev_err(card->dev, |
@@ -1596,7 +1103,7 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1596 | return 0; | 1103 | return 0; |
1597 | } | 1104 | } |
1598 | 1105 | ||
1599 | static int soc_probe_dai_link(struct snd_soc_card *card, int num) | 1106 | static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) |
1600 | { | 1107 | { |
1601 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1108 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1602 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1109 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
@@ -1605,7 +1112,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) | |||
1605 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; | 1112 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; |
1606 | int ret; | 1113 | int ret; |
1607 | 1114 | ||
1608 | dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num); | 1115 | dev_dbg(card->dev, "probe %s dai link %d late %d\n", |
1116 | card->name, num, order); | ||
1609 | 1117 | ||
1610 | /* config components */ | 1118 | /* config components */ |
1611 | codec_dai->codec = codec; | 1119 | codec_dai->codec = codec; |
@@ -1617,7 +1125,8 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) | |||
1617 | rtd->pmdown_time = pmdown_time; | 1125 | rtd->pmdown_time = pmdown_time; |
1618 | 1126 | ||
1619 | /* probe the cpu_dai */ | 1127 | /* probe the cpu_dai */ |
1620 | if (!cpu_dai->probed) { | 1128 | if (!cpu_dai->probed && |
1129 | cpu_dai->driver->probe_order == order) { | ||
1621 | if (!try_module_get(cpu_dai->dev->driver->owner)) | 1130 | if (!try_module_get(cpu_dai->dev->driver->owner)) |
1622 | return -ENODEV; | 1131 | return -ENODEV; |
1623 | 1132 | ||
@@ -1636,33 +1145,23 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) | |||
1636 | } | 1145 | } |
1637 | 1146 | ||
1638 | /* probe the CODEC */ | 1147 | /* probe the CODEC */ |
1639 | if (!codec->probed) { | 1148 | if (!codec->probed && |
1149 | codec->driver->probe_order == order) { | ||
1640 | ret = soc_probe_codec(card, codec); | 1150 | ret = soc_probe_codec(card, codec); |
1641 | if (ret < 0) | 1151 | if (ret < 0) |
1642 | return ret; | 1152 | return ret; |
1643 | } | 1153 | } |
1644 | 1154 | ||
1645 | /* probe the platform */ | 1155 | /* probe the platform */ |
1646 | if (!platform->probed) { | 1156 | if (!platform->probed && |
1647 | if (!try_module_get(platform->dev->driver->owner)) | 1157 | platform->driver->probe_order == order) { |
1648 | return -ENODEV; | 1158 | ret = soc_probe_platform(card, platform); |
1649 | 1159 | if (ret < 0) | |
1650 | if (platform->driver->probe) { | 1160 | return ret; |
1651 | ret = platform->driver->probe(platform); | ||
1652 | if (ret < 0) { | ||
1653 | printk(KERN_ERR "asoc: failed to probe platform %s\n", | ||
1654 | platform->name); | ||
1655 | module_put(platform->dev->driver->owner); | ||
1656 | return ret; | ||
1657 | } | ||
1658 | } | ||
1659 | /* mark platform as probed and add to card platform list */ | ||
1660 | platform->probed = 1; | ||
1661 | list_add(&platform->card_list, &card->platform_dev_list); | ||
1662 | } | 1161 | } |
1663 | 1162 | ||
1664 | /* probe the CODEC DAI */ | 1163 | /* probe the CODEC DAI */ |
1665 | if (!codec_dai->probed) { | 1164 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { |
1666 | if (codec_dai->driver->probe) { | 1165 | if (codec_dai->driver->probe) { |
1667 | ret = codec_dai->driver->probe(codec_dai); | 1166 | ret = codec_dai->driver->probe(codec_dai); |
1668 | if (ret < 0) { | 1167 | if (ret < 0) { |
@@ -1677,8 +1176,9 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) | |||
1677 | list_add(&codec_dai->card_list, &card->dai_dev_list); | 1176 | list_add(&codec_dai->card_list, &card->dai_dev_list); |
1678 | } | 1177 | } |
1679 | 1178 | ||
1680 | /* DAPM dai link stream work */ | 1179 | /* complete DAI probe during last probe */ |
1681 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); | 1180 | if (order != SND_SOC_COMP_ORDER_LAST) |
1181 | return 0; | ||
1682 | 1182 | ||
1683 | ret = soc_post_component_init(card, codec, num, 0); | 1183 | ret = soc_post_component_init(card, codec, num, 0); |
1684 | if (ret) | 1184 | if (ret) |
@@ -1817,7 +1317,7 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1817 | struct snd_soc_codec *codec; | 1317 | struct snd_soc_codec *codec; |
1818 | struct snd_soc_codec_conf *codec_conf; | 1318 | struct snd_soc_codec_conf *codec_conf; |
1819 | enum snd_soc_compress_type compress_type; | 1319 | enum snd_soc_compress_type compress_type; |
1820 | int ret, i; | 1320 | int ret, i, order; |
1821 | 1321 | ||
1822 | mutex_lock(&card->mutex); | 1322 | mutex_lock(&card->mutex); |
1823 | 1323 | ||
@@ -1895,12 +1395,16 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1895 | goto card_probe_error; | 1395 | goto card_probe_error; |
1896 | } | 1396 | } |
1897 | 1397 | ||
1898 | for (i = 0; i < card->num_links; i++) { | 1398 | /* early DAI link probe */ |
1899 | ret = soc_probe_dai_link(card, i); | 1399 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; |
1900 | if (ret < 0) { | 1400 | order++) { |
1901 | pr_err("asoc: failed to instantiate card %s: %d\n", | 1401 | for (i = 0; i < card->num_links; i++) { |
1402 | ret = soc_probe_dai_link(card, i, order); | ||
1403 | if (ret < 0) { | ||
1404 | pr_err("asoc: failed to instantiate card %s: %d\n", | ||
1902 | card->name, ret); | 1405 | card->name, ret); |
1903 | goto probe_dai_err; | 1406 | goto probe_dai_err; |
1407 | } | ||
1904 | } | 1408 | } |
1905 | } | 1409 | } |
1906 | 1410 | ||
@@ -2096,67 +1600,6 @@ static struct platform_driver soc_driver = { | |||
2096 | .remove = soc_remove, | 1600 | .remove = soc_remove, |
2097 | }; | 1601 | }; |
2098 | 1602 | ||
2099 | /* create a new pcm */ | ||
2100 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | ||
2101 | { | ||
2102 | struct snd_soc_codec *codec = rtd->codec; | ||
2103 | struct snd_soc_platform *platform = rtd->platform; | ||
2104 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
2105 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
2106 | struct snd_pcm *pcm; | ||
2107 | char new_name[64]; | ||
2108 | int ret = 0, playback = 0, capture = 0; | ||
2109 | |||
2110 | /* check client and interface hw capabilities */ | ||
2111 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | ||
2112 | rtd->dai_link->stream_name, codec_dai->name, num); | ||
2113 | |||
2114 | if (codec_dai->driver->playback.channels_min) | ||
2115 | playback = 1; | ||
2116 | if (codec_dai->driver->capture.channels_min) | ||
2117 | capture = 1; | ||
2118 | |||
2119 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); | ||
2120 | ret = snd_pcm_new(rtd->card->snd_card, new_name, | ||
2121 | num, playback, capture, &pcm); | ||
2122 | if (ret < 0) { | ||
2123 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | ||
2124 | return ret; | ||
2125 | } | ||
2126 | |||
2127 | rtd->pcm = pcm; | ||
2128 | pcm->private_data = rtd; | ||
2129 | if (platform->driver->ops) { | ||
2130 | soc_pcm_ops.mmap = platform->driver->ops->mmap; | ||
2131 | soc_pcm_ops.pointer = platform->driver->ops->pointer; | ||
2132 | soc_pcm_ops.ioctl = platform->driver->ops->ioctl; | ||
2133 | soc_pcm_ops.copy = platform->driver->ops->copy; | ||
2134 | soc_pcm_ops.silence = platform->driver->ops->silence; | ||
2135 | soc_pcm_ops.ack = platform->driver->ops->ack; | ||
2136 | soc_pcm_ops.page = platform->driver->ops->page; | ||
2137 | } | ||
2138 | |||
2139 | if (playback) | ||
2140 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); | ||
2141 | |||
2142 | if (capture) | ||
2143 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); | ||
2144 | |||
2145 | if (platform->driver->pcm_new) { | ||
2146 | ret = platform->driver->pcm_new(rtd->card->snd_card, | ||
2147 | codec_dai, pcm); | ||
2148 | if (ret < 0) { | ||
2149 | pr_err("asoc: platform pcm constructor failed\n"); | ||
2150 | return ret; | ||
2151 | } | ||
2152 | } | ||
2153 | |||
2154 | pcm->private_free = platform->driver->pcm_free; | ||
2155 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | ||
2156 | cpu_dai->name); | ||
2157 | return ret; | ||
2158 | } | ||
2159 | |||
2160 | /** | 1603 | /** |
2161 | * snd_soc_codec_volatile_register: Report if a register is volatile. | 1604 | * snd_soc_codec_volatile_register: Report if a register is volatile. |
2162 | * | 1605 | * |
@@ -2211,6 +1654,38 @@ int snd_soc_codec_writable_register(struct snd_soc_codec *codec, | |||
2211 | } | 1654 | } |
2212 | EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register); | 1655 | EXPORT_SYMBOL_GPL(snd_soc_codec_writable_register); |
2213 | 1656 | ||
1657 | int snd_soc_platform_read(struct snd_soc_platform *platform, | ||
1658 | unsigned int reg) | ||
1659 | { | ||
1660 | unsigned int ret; | ||
1661 | |||
1662 | if (!platform->driver->read) { | ||
1663 | dev_err(platform->dev, "platform has no read back\n"); | ||
1664 | return -1; | ||
1665 | } | ||
1666 | |||
1667 | ret = platform->driver->read(platform, reg); | ||
1668 | dev_dbg(platform->dev, "read %x => %x\n", reg, ret); | ||
1669 | trace_snd_soc_preg_read(platform, reg, ret); | ||
1670 | |||
1671 | return ret; | ||
1672 | } | ||
1673 | EXPORT_SYMBOL_GPL(snd_soc_platform_read); | ||
1674 | |||
1675 | int snd_soc_platform_write(struct snd_soc_platform *platform, | ||
1676 | unsigned int reg, unsigned int val) | ||
1677 | { | ||
1678 | if (!platform->driver->write) { | ||
1679 | dev_err(platform->dev, "platform has no write back\n"); | ||
1680 | return -1; | ||
1681 | } | ||
1682 | |||
1683 | dev_dbg(platform->dev, "write %x = %x\n", reg, val); | ||
1684 | trace_snd_soc_preg_write(platform, reg, val); | ||
1685 | return platform->driver->write(platform, reg, val); | ||
1686 | } | ||
1687 | EXPORT_SYMBOL_GPL(snd_soc_platform_write); | ||
1688 | |||
2214 | /** | 1689 | /** |
2215 | * snd_soc_new_ac97_codec - initailise AC97 device | 1690 | * snd_soc_new_ac97_codec - initailise AC97 device |
2216 | * @codec: audio codec | 1691 | * @codec: audio codec |
@@ -2323,7 +1798,7 @@ int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | |||
2323 | return ret; | 1798 | return ret; |
2324 | 1799 | ||
2325 | old = ret; | 1800 | old = ret; |
2326 | new = (old & ~mask) | value; | 1801 | new = (old & ~mask) | (value & mask); |
2327 | change = old != new; | 1802 | change = old != new; |
2328 | if (change) { | 1803 | if (change) { |
2329 | ret = snd_soc_write(codec, reg, new); | 1804 | ret = snd_soc_write(codec, reg, new); |
@@ -2490,6 +1965,36 @@ int snd_soc_add_controls(struct snd_soc_codec *codec, | |||
2490 | EXPORT_SYMBOL_GPL(snd_soc_add_controls); | 1965 | EXPORT_SYMBOL_GPL(snd_soc_add_controls); |
2491 | 1966 | ||
2492 | /** | 1967 | /** |
1968 | * snd_soc_add_platform_controls - add an array of controls to a platform. | ||
1969 | * Convienience function to add a list of controls. | ||
1970 | * | ||
1971 | * @platform: platform to add controls to | ||
1972 | * @controls: array of controls to add | ||
1973 | * @num_controls: number of elements in the array | ||
1974 | * | ||
1975 | * Return 0 for success, else error. | ||
1976 | */ | ||
1977 | int snd_soc_add_platform_controls(struct snd_soc_platform *platform, | ||
1978 | const struct snd_kcontrol_new *controls, int num_controls) | ||
1979 | { | ||
1980 | struct snd_card *card = platform->card->snd_card; | ||
1981 | int err, i; | ||
1982 | |||
1983 | for (i = 0; i < num_controls; i++) { | ||
1984 | const struct snd_kcontrol_new *control = &controls[i]; | ||
1985 | err = snd_ctl_add(card, snd_soc_cnew(control, platform, | ||
1986 | control->name, NULL)); | ||
1987 | if (err < 0) { | ||
1988 | dev_err(platform->dev, "Failed to add %s %d\n",control->name, err); | ||
1989 | return err; | ||
1990 | } | ||
1991 | } | ||
1992 | |||
1993 | return 0; | ||
1994 | } | ||
1995 | EXPORT_SYMBOL_GPL(snd_soc_add_platform_controls); | ||
1996 | |||
1997 | /** | ||
2493 | * snd_soc_info_enum_double - enumerated double mixer info callback | 1998 | * snd_soc_info_enum_double - enumerated double mixer info callback |
2494 | * @kcontrol: mixer control | 1999 | * @kcontrol: mixer control |
2495 | * @uinfo: control element information | 2000 | * @uinfo: control element information |
@@ -3633,6 +3138,8 @@ int snd_soc_register_platform(struct device *dev, | |||
3633 | 3138 | ||
3634 | platform->dev = dev; | 3139 | platform->dev = dev; |
3635 | platform->driver = platform_drv; | 3140 | platform->driver = platform_drv; |
3141 | platform->dapm.dev = dev; | ||
3142 | platform->dapm.platform = platform; | ||
3636 | 3143 | ||
3637 | mutex_lock(&client_mutex); | 3144 | mutex_lock(&client_mutex); |
3638 | list_add(&platform->list, &platform_list); | 3145 | list_add(&platform->list, &platform_list); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 32ab7fc4579a..54fa2e5e3078 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -124,6 +124,51 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
124 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); | 124 | return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); |
125 | } | 125 | } |
126 | 126 | ||
127 | static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) | ||
128 | { | ||
129 | if (w->codec) | ||
130 | return snd_soc_read(w->codec, reg); | ||
131 | else if (w->platform) | ||
132 | return snd_soc_platform_read(w->platform, reg); | ||
133 | |||
134 | dev_err(w->dapm->dev, "no valid widget read method\n"); | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) | ||
139 | { | ||
140 | if (w->codec) | ||
141 | return snd_soc_write(w->codec, reg, val); | ||
142 | else if (w->platform) | ||
143 | return snd_soc_platform_write(w->platform, reg, val); | ||
144 | |||
145 | dev_err(w->dapm->dev, "no valid widget write method\n"); | ||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | static int soc_widget_update_bits(struct snd_soc_dapm_widget *w, | ||
150 | unsigned short reg, unsigned int mask, unsigned int value) | ||
151 | { | ||
152 | int change; | ||
153 | unsigned int old, new; | ||
154 | int ret; | ||
155 | |||
156 | ret = soc_widget_read(w, reg); | ||
157 | if (ret < 0) | ||
158 | return ret; | ||
159 | |||
160 | old = ret; | ||
161 | new = (old & ~mask) | (value & mask); | ||
162 | change = old != new; | ||
163 | if (change) { | ||
164 | ret = soc_widget_write(w, reg, new); | ||
165 | if (ret < 0) | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | return change; | ||
170 | } | ||
171 | |||
127 | /** | 172 | /** |
128 | * snd_soc_dapm_set_bias_level - set the bias level for the system | 173 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
129 | * @dapm: DAPM context | 174 | * @dapm: DAPM context |
@@ -139,39 +184,26 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, | |||
139 | struct snd_soc_card *card = dapm->card; | 184 | struct snd_soc_card *card = dapm->card; |
140 | int ret = 0; | 185 | int ret = 0; |
141 | 186 | ||
142 | switch (level) { | ||
143 | case SND_SOC_BIAS_ON: | ||
144 | dev_dbg(dapm->dev, "Setting full bias\n"); | ||
145 | break; | ||
146 | case SND_SOC_BIAS_PREPARE: | ||
147 | dev_dbg(dapm->dev, "Setting bias prepare\n"); | ||
148 | break; | ||
149 | case SND_SOC_BIAS_STANDBY: | ||
150 | dev_dbg(dapm->dev, "Setting standby bias\n"); | ||
151 | break; | ||
152 | case SND_SOC_BIAS_OFF: | ||
153 | dev_dbg(dapm->dev, "Setting bias off\n"); | ||
154 | break; | ||
155 | default: | ||
156 | dev_err(dapm->dev, "Setting invalid bias %d\n", level); | ||
157 | return -EINVAL; | ||
158 | } | ||
159 | |||
160 | trace_snd_soc_bias_level_start(card, level); | 187 | trace_snd_soc_bias_level_start(card, level); |
161 | 188 | ||
162 | if (card && card->set_bias_level) | 189 | if (card && card->set_bias_level) |
163 | ret = card->set_bias_level(card, level); | 190 | ret = card->set_bias_level(card, dapm, level); |
164 | if (ret == 0) { | 191 | if (ret != 0) |
165 | if (dapm->codec && dapm->codec->driver->set_bias_level) | 192 | goto out; |
166 | ret = dapm->codec->driver->set_bias_level(dapm->codec, level); | 193 | |
194 | if (dapm->codec) { | ||
195 | if (dapm->codec->driver->set_bias_level) | ||
196 | ret = dapm->codec->driver->set_bias_level(dapm->codec, | ||
197 | level); | ||
167 | else | 198 | else |
168 | dapm->bias_level = level; | 199 | dapm->bias_level = level; |
169 | } | 200 | } |
170 | if (ret == 0) { | 201 | if (ret != 0) |
171 | if (card && card->set_bias_level_post) | 202 | goto out; |
172 | ret = card->set_bias_level_post(card, level); | ||
173 | } | ||
174 | 203 | ||
204 | if (card && card->set_bias_level_post) | ||
205 | ret = card->set_bias_level_post(card, dapm, level); | ||
206 | out: | ||
175 | trace_snd_soc_bias_level_done(card, level); | 207 | trace_snd_soc_bias_level_done(card, level); |
176 | 208 | ||
177 | return ret; | 209 | return ret; |
@@ -194,7 +226,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
194 | unsigned int mask = (1 << fls(max)) - 1; | 226 | unsigned int mask = (1 << fls(max)) - 1; |
195 | unsigned int invert = mc->invert; | 227 | unsigned int invert = mc->invert; |
196 | 228 | ||
197 | val = snd_soc_read(w->codec, reg); | 229 | val = soc_widget_read(w, reg); |
198 | val = (val >> shift) & mask; | 230 | val = (val >> shift) & mask; |
199 | 231 | ||
200 | if ((invert && !val) || (!invert && val)) | 232 | if ((invert && !val) || (!invert && val)) |
@@ -209,8 +241,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
209 | int val, item, bitmask; | 241 | int val, item, bitmask; |
210 | 242 | ||
211 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 243 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
212 | ; | 244 | ; |
213 | val = snd_soc_read(w->codec, e->reg); | 245 | val = soc_widget_read(w, e->reg); |
214 | item = (val >> e->shift_l) & (bitmask - 1); | 246 | item = (val >> e->shift_l) & (bitmask - 1); |
215 | 247 | ||
216 | p->connect = 0; | 248 | p->connect = 0; |
@@ -240,7 +272,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
240 | w->kcontrol_news[i].private_value; | 272 | w->kcontrol_news[i].private_value; |
241 | int val, item; | 273 | int val, item; |
242 | 274 | ||
243 | val = snd_soc_read(w->codec, e->reg); | 275 | val = soc_widget_read(w, e->reg); |
244 | val = (val >> e->shift_l) & e->mask; | 276 | val = (val >> e->shift_l) & e->mask; |
245 | for (item = 0; item < e->max; item++) { | 277 | for (item = 0; item < e->max; item++) { |
246 | if (val == e->values[item]) | 278 | if (val == e->values[item]) |
@@ -606,6 +638,9 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | |||
606 | } | 638 | } |
607 | 639 | ||
608 | list_for_each_entry(path, &widget->sinks, list_source) { | 640 | list_for_each_entry(path, &widget->sinks, list_source) { |
641 | if (path->weak) | ||
642 | continue; | ||
643 | |||
609 | if (path->walked) | 644 | if (path->walked) |
610 | continue; | 645 | continue; |
611 | 646 | ||
@@ -656,6 +691,9 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
656 | } | 691 | } |
657 | 692 | ||
658 | list_for_each_entry(path, &widget->sources, list_sink) { | 693 | list_for_each_entry(path, &widget->sources, list_sink) { |
694 | if (path->weak) | ||
695 | continue; | ||
696 | |||
659 | if (path->walked) | 697 | if (path->walked) |
660 | continue; | 698 | continue; |
661 | 699 | ||
@@ -681,7 +719,7 @@ int dapm_reg_event(struct snd_soc_dapm_widget *w, | |||
681 | else | 719 | else |
682 | val = w->off_val; | 720 | val = w->off_val; |
683 | 721 | ||
684 | snd_soc_update_bits(w->codec, -(w->reg + 1), | 722 | soc_widget_update_bits(w, -(w->reg + 1), |
685 | w->mask << w->shift, val << w->shift); | 723 | w->mask << w->shift, val << w->shift); |
686 | 724 | ||
687 | return 0; | 725 | return 0; |
@@ -737,6 +775,9 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
737 | 775 | ||
738 | /* Check if one of our outputs is connected */ | 776 | /* Check if one of our outputs is connected */ |
739 | list_for_each_entry(path, &w->sinks, list_source) { | 777 | list_for_each_entry(path, &w->sinks, list_source) { |
778 | if (path->weak) | ||
779 | continue; | ||
780 | |||
740 | if (path->connected && | 781 | if (path->connected && |
741 | !path->connected(path->source, path->sink)) | 782 | !path->connected(path->source, path->sink)) |
742 | continue; | 783 | continue; |
@@ -885,11 +926,17 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
885 | } | 926 | } |
886 | 927 | ||
887 | if (reg >= 0) { | 928 | if (reg >= 0) { |
929 | /* Any widget will do, they should all be updating the | ||
930 | * same register. | ||
931 | */ | ||
932 | w = list_first_entry(pending, struct snd_soc_dapm_widget, | ||
933 | power_list); | ||
934 | |||
888 | pop_dbg(dapm->dev, card->pop_time, | 935 | pop_dbg(dapm->dev, card->pop_time, |
889 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", | 936 | "pop test : Applying 0x%x/0x%x to %x in %dms\n", |
890 | value, mask, reg, card->pop_time); | 937 | value, mask, reg, card->pop_time); |
891 | pop_wait(card->pop_time); | 938 | pop_wait(card->pop_time); |
892 | snd_soc_update_bits(dapm->codec, reg, mask, value); | 939 | soc_widget_update_bits(w, reg, mask, value); |
893 | } | 940 | } |
894 | 941 | ||
895 | list_for_each_entry(w, pending, power_list) { | 942 | list_for_each_entry(w, pending, power_list) { |
@@ -1041,16 +1088,17 @@ static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) | |||
1041 | struct snd_soc_dapm_context *d = data; | 1088 | struct snd_soc_dapm_context *d = data; |
1042 | int ret; | 1089 | int ret; |
1043 | 1090 | ||
1044 | if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { | 1091 | /* If we're off and we're not supposed to be go into STANDBY */ |
1092 | if (d->bias_level == SND_SOC_BIAS_OFF && | ||
1093 | d->target_bias_level != SND_SOC_BIAS_OFF) { | ||
1045 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | 1094 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); |
1046 | if (ret != 0) | 1095 | if (ret != 0) |
1047 | dev_err(d->dev, | 1096 | dev_err(d->dev, |
1048 | "Failed to turn on bias: %d\n", ret); | 1097 | "Failed to turn on bias: %d\n", ret); |
1049 | } | 1098 | } |
1050 | 1099 | ||
1051 | /* If we're changing to all on or all off then prepare */ | 1100 | /* Prepare for a STADDBY->ON or ON->STANDBY transition */ |
1052 | if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || | 1101 | if (d->bias_level != d->target_bias_level) { |
1053 | (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) { | ||
1054 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); | 1102 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); |
1055 | if (ret != 0) | 1103 | if (ret != 0) |
1056 | dev_err(d->dev, | 1104 | dev_err(d->dev, |
@@ -1067,7 +1115,9 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) | |||
1067 | int ret; | 1115 | int ret; |
1068 | 1116 | ||
1069 | /* If we just powered the last thing off drop to standby bias */ | 1117 | /* If we just powered the last thing off drop to standby bias */ |
1070 | if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { | 1118 | if (d->bias_level == SND_SOC_BIAS_PREPARE && |
1119 | (d->target_bias_level == SND_SOC_BIAS_STANDBY || | ||
1120 | d->target_bias_level == SND_SOC_BIAS_OFF)) { | ||
1071 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | 1121 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); |
1072 | if (ret != 0) | 1122 | if (ret != 0) |
1073 | dev_err(d->dev, "Failed to apply standby bias: %d\n", | 1123 | dev_err(d->dev, "Failed to apply standby bias: %d\n", |
@@ -1075,14 +1125,16 @@ static void dapm_post_sequence_async(void *data, async_cookie_t cookie) | |||
1075 | } | 1125 | } |
1076 | 1126 | ||
1077 | /* If we're in standby and can support bias off then do that */ | 1127 | /* If we're in standby and can support bias off then do that */ |
1078 | if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) { | 1128 | if (d->bias_level == SND_SOC_BIAS_STANDBY && |
1129 | d->target_bias_level == SND_SOC_BIAS_OFF) { | ||
1079 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); | 1130 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); |
1080 | if (ret != 0) | 1131 | if (ret != 0) |
1081 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); | 1132 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); |
1082 | } | 1133 | } |
1083 | 1134 | ||
1084 | /* If we just powered up then move to active bias */ | 1135 | /* If we just powered up then move to active bias */ |
1085 | if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { | 1136 | if (d->bias_level == SND_SOC_BIAS_PREPARE && |
1137 | d->target_bias_level == SND_SOC_BIAS_ON) { | ||
1086 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); | 1138 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); |
1087 | if (ret != 0) | 1139 | if (ret != 0) |
1088 | dev_err(d->dev, "Failed to apply active bias: %d\n", | 1140 | dev_err(d->dev, "Failed to apply active bias: %d\n", |
@@ -1107,13 +1159,19 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1107 | LIST_HEAD(up_list); | 1159 | LIST_HEAD(up_list); |
1108 | LIST_HEAD(down_list); | 1160 | LIST_HEAD(down_list); |
1109 | LIST_HEAD(async_domain); | 1161 | LIST_HEAD(async_domain); |
1162 | enum snd_soc_bias_level bias; | ||
1110 | int power; | 1163 | int power; |
1111 | 1164 | ||
1112 | trace_snd_soc_dapm_start(card); | 1165 | trace_snd_soc_dapm_start(card); |
1113 | 1166 | ||
1114 | list_for_each_entry(d, &card->dapm_list, list) | 1167 | list_for_each_entry(d, &card->dapm_list, list) { |
1115 | if (d->n_widgets || d->codec == NULL) | 1168 | if (d->n_widgets || d->codec == NULL) { |
1116 | d->dev_power = 0; | 1169 | if (d->idle_bias_off) |
1170 | d->target_bias_level = SND_SOC_BIAS_OFF; | ||
1171 | else | ||
1172 | d->target_bias_level = SND_SOC_BIAS_STANDBY; | ||
1173 | } | ||
1174 | } | ||
1117 | 1175 | ||
1118 | /* Check which widgets we need to power and store them in | 1176 | /* Check which widgets we need to power and store them in |
1119 | * lists indicating if they should be powered up or down. | 1177 | * lists indicating if they should be powered up or down. |
@@ -1135,8 +1193,27 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1135 | power = w->power_check(w); | 1193 | power = w->power_check(w); |
1136 | else | 1194 | else |
1137 | power = 1; | 1195 | power = 1; |
1138 | if (power) | 1196 | |
1139 | w->dapm->dev_power = 1; | 1197 | if (power) { |
1198 | d = w->dapm; | ||
1199 | |||
1200 | /* Supplies and micbiases only bring | ||
1201 | * the context up to STANDBY as unless | ||
1202 | * something else is active and | ||
1203 | * passing audio they generally don't | ||
1204 | * require full power. | ||
1205 | */ | ||
1206 | switch (w->id) { | ||
1207 | case snd_soc_dapm_supply: | ||
1208 | case snd_soc_dapm_micbias: | ||
1209 | if (d->target_bias_level < SND_SOC_BIAS_STANDBY) | ||
1210 | d->target_bias_level = SND_SOC_BIAS_STANDBY; | ||
1211 | break; | ||
1212 | default: | ||
1213 | d->target_bias_level = SND_SOC_BIAS_ON; | ||
1214 | break; | ||
1215 | } | ||
1216 | } | ||
1140 | 1217 | ||
1141 | if (w->power == power) | 1218 | if (w->power == power) |
1142 | continue; | 1219 | continue; |
@@ -1160,24 +1237,19 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1160 | switch (event) { | 1237 | switch (event) { |
1161 | case SND_SOC_DAPM_STREAM_START: | 1238 | case SND_SOC_DAPM_STREAM_START: |
1162 | case SND_SOC_DAPM_STREAM_RESUME: | 1239 | case SND_SOC_DAPM_STREAM_RESUME: |
1163 | dapm->dev_power = 1; | 1240 | dapm->target_bias_level = SND_SOC_BIAS_ON; |
1164 | break; | 1241 | break; |
1165 | case SND_SOC_DAPM_STREAM_STOP: | 1242 | case SND_SOC_DAPM_STREAM_STOP: |
1166 | dapm->dev_power = !!dapm->codec->active; | 1243 | if (dapm->codec->active) |
1244 | dapm->target_bias_level = SND_SOC_BIAS_ON; | ||
1245 | else | ||
1246 | dapm->target_bias_level = SND_SOC_BIAS_STANDBY; | ||
1167 | break; | 1247 | break; |
1168 | case SND_SOC_DAPM_STREAM_SUSPEND: | 1248 | case SND_SOC_DAPM_STREAM_SUSPEND: |
1169 | dapm->dev_power = 0; | 1249 | dapm->target_bias_level = SND_SOC_BIAS_STANDBY; |
1170 | break; | 1250 | break; |
1171 | case SND_SOC_DAPM_STREAM_NOP: | 1251 | case SND_SOC_DAPM_STREAM_NOP: |
1172 | switch (dapm->bias_level) { | 1252 | dapm->target_bias_level = dapm->bias_level; |
1173 | case SND_SOC_BIAS_STANDBY: | ||
1174 | case SND_SOC_BIAS_OFF: | ||
1175 | dapm->dev_power = 0; | ||
1176 | break; | ||
1177 | default: | ||
1178 | dapm->dev_power = 1; | ||
1179 | break; | ||
1180 | } | ||
1181 | break; | 1253 | break; |
1182 | default: | 1254 | default: |
1183 | break; | 1255 | break; |
@@ -1185,12 +1257,12 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1185 | } | 1257 | } |
1186 | 1258 | ||
1187 | /* Force all contexts in the card to the same bias state */ | 1259 | /* Force all contexts in the card to the same bias state */ |
1188 | power = 0; | 1260 | bias = SND_SOC_BIAS_OFF; |
1189 | list_for_each_entry(d, &card->dapm_list, list) | 1261 | list_for_each_entry(d, &card->dapm_list, list) |
1190 | if (d->dev_power) | 1262 | if (d->target_bias_level > bias) |
1191 | power = 1; | 1263 | bias = d->target_bias_level; |
1192 | list_for_each_entry(d, &card->dapm_list, list) | 1264 | list_for_each_entry(d, &card->dapm_list, list) |
1193 | d->dev_power = power; | 1265 | d->target_bias_level = bias; |
1194 | 1266 | ||
1195 | 1267 | ||
1196 | /* Run all the bias changes in parallel */ | 1268 | /* Run all the bias changes in parallel */ |
@@ -1794,6 +1866,84 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, | |||
1794 | } | 1866 | } |
1795 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | 1867 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); |
1796 | 1868 | ||
1869 | static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, | ||
1870 | const struct snd_soc_dapm_route *route) | ||
1871 | { | ||
1872 | struct snd_soc_dapm_widget *source = dapm_find_widget(dapm, | ||
1873 | route->source, | ||
1874 | true); | ||
1875 | struct snd_soc_dapm_widget *sink = dapm_find_widget(dapm, | ||
1876 | route->sink, | ||
1877 | true); | ||
1878 | struct snd_soc_dapm_path *path; | ||
1879 | int count = 0; | ||
1880 | |||
1881 | if (!source) { | ||
1882 | dev_err(dapm->dev, "Unable to find source %s for weak route\n", | ||
1883 | route->source); | ||
1884 | return -ENODEV; | ||
1885 | } | ||
1886 | |||
1887 | if (!sink) { | ||
1888 | dev_err(dapm->dev, "Unable to find sink %s for weak route\n", | ||
1889 | route->sink); | ||
1890 | return -ENODEV; | ||
1891 | } | ||
1892 | |||
1893 | if (route->control || route->connected) | ||
1894 | dev_warn(dapm->dev, "Ignoring control for weak route %s->%s\n", | ||
1895 | route->source, route->sink); | ||
1896 | |||
1897 | list_for_each_entry(path, &source->sinks, list_source) { | ||
1898 | if (path->sink == sink) { | ||
1899 | path->weak = 1; | ||
1900 | count++; | ||
1901 | } | ||
1902 | } | ||
1903 | |||
1904 | if (count == 0) | ||
1905 | dev_err(dapm->dev, "No path found for weak route %s->%s\n", | ||
1906 | route->source, route->sink); | ||
1907 | if (count > 1) | ||
1908 | dev_warn(dapm->dev, "%d paths found for weak route %s->%s\n", | ||
1909 | count, route->source, route->sink); | ||
1910 | |||
1911 | return 0; | ||
1912 | } | ||
1913 | |||
1914 | /** | ||
1915 | * snd_soc_dapm_weak_routes - Mark routes between DAPM widgets as weak | ||
1916 | * @dapm: DAPM context | ||
1917 | * @route: audio routes | ||
1918 | * @num: number of routes | ||
1919 | * | ||
1920 | * Mark existing routes matching those specified in the passed array | ||
1921 | * as being weak, meaning that they are ignored for the purpose of | ||
1922 | * power decisions. The main intended use case is for sidetone paths | ||
1923 | * which couple audio between other independent paths if they are both | ||
1924 | * active in order to make the combination work better at the user | ||
1925 | * level but which aren't intended to be "used". | ||
1926 | * | ||
1927 | * Note that CODEC drivers should not use this as sidetone type paths | ||
1928 | * can frequently also be used as bypass paths. | ||
1929 | */ | ||
1930 | int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, | ||
1931 | const struct snd_soc_dapm_route *route, int num) | ||
1932 | { | ||
1933 | int i, err; | ||
1934 | int ret = 0; | ||
1935 | |||
1936 | for (i = 0; i < num; i++) { | ||
1937 | err = snd_soc_dapm_weak_route(dapm, route); | ||
1938 | if (err) | ||
1939 | ret = err; | ||
1940 | route++; | ||
1941 | } | ||
1942 | |||
1943 | return ret; | ||
1944 | } | ||
1945 | EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); | ||
1946 | |||
1797 | /** | 1947 | /** |
1798 | * snd_soc_dapm_new_widgets - add new dapm widgets | 1948 | * snd_soc_dapm_new_widgets - add new dapm widgets |
1799 | * @dapm: DAPM context | 1949 | * @dapm: DAPM context |
@@ -1865,7 +2015,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) | |||
1865 | 2015 | ||
1866 | /* Read the initial power state from the device */ | 2016 | /* Read the initial power state from the device */ |
1867 | if (w->reg >= 0) { | 2017 | if (w->reg >= 0) { |
1868 | val = snd_soc_read(w->codec, w->reg); | 2018 | val = soc_widget_read(w, w->reg); |
1869 | val &= 1 << w->shift; | 2019 | val &= 1 << w->shift; |
1870 | if (w->invert) | 2020 | if (w->invert) |
1871 | val = !val; | 2021 | val = !val; |
@@ -2353,6 +2503,7 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2353 | dapm->n_widgets++; | 2503 | dapm->n_widgets++; |
2354 | w->dapm = dapm; | 2504 | w->dapm = dapm; |
2355 | w->codec = dapm->codec; | 2505 | w->codec = dapm->codec; |
2506 | w->platform = dapm->platform; | ||
2356 | INIT_LIST_HEAD(&w->sources); | 2507 | INIT_LIST_HEAD(&w->sources); |
2357 | INIT_LIST_HEAD(&w->sinks); | 2508 | INIT_LIST_HEAD(&w->sinks); |
2358 | INIT_LIST_HEAD(&w->list); | 2509 | INIT_LIST_HEAD(&w->list); |
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c new file mode 100644 index 000000000000..cca490c80589 --- /dev/null +++ b/sound/soc/soc-io.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* | ||
2 | * soc-io.c -- ASoC register I/O helpers | ||
3 | * | ||
4 | * Copyright 2009-2011 Wolfson Microelectronics PLC. | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <sound/soc.h> | ||
17 | |||
18 | #include <trace/events/asoc.h> | ||
19 | |||
20 | #ifdef CONFIG_SPI_MASTER | ||
21 | static int do_spi_write(void *control, const char *data, int len) | ||
22 | { | ||
23 | struct spi_device *spi = control; | ||
24 | int ret; | ||
25 | |||
26 | ret = spi_write(spi, data, len); | ||
27 | if (ret < 0) | ||
28 | return ret; | ||
29 | |||
30 | return len; | ||
31 | } | ||
32 | #endif | ||
33 | |||
34 | static int do_hw_write(struct snd_soc_codec *codec, unsigned int reg, | ||
35 | unsigned int value, const void *data, int len) | ||
36 | { | ||
37 | int ret; | ||
38 | |||
39 | if (!snd_soc_codec_volatile_register(codec, reg) && | ||
40 | reg < codec->driver->reg_cache_size && | ||
41 | !codec->cache_bypass) { | ||
42 | ret = snd_soc_cache_write(codec, reg, value); | ||
43 | if (ret < 0) | ||
44 | return -1; | ||
45 | } | ||
46 | |||
47 | if (codec->cache_only) { | ||
48 | codec->cache_sync = 1; | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | ret = codec->hw_write(codec->control_data, data, len); | ||
53 | if (ret == len) | ||
54 | return 0; | ||
55 | if (ret < 0) | ||
56 | return ret; | ||
57 | else | ||
58 | return -EIO; | ||
59 | } | ||
60 | |||
61 | static unsigned int hw_read(struct snd_soc_codec *codec, unsigned int reg) | ||
62 | { | ||
63 | int ret; | ||
64 | unsigned int val; | ||
65 | |||
66 | if (reg >= codec->driver->reg_cache_size || | ||
67 | snd_soc_codec_volatile_register(codec, reg) || | ||
68 | codec->cache_bypass) { | ||
69 | if (codec->cache_only) | ||
70 | return -1; | ||
71 | |||
72 | BUG_ON(!codec->hw_read); | ||
73 | return codec->hw_read(codec, reg); | ||
74 | } | ||
75 | |||
76 | ret = snd_soc_cache_read(codec, reg, &val); | ||
77 | if (ret < 0) | ||
78 | return -1; | ||
79 | return val; | ||
80 | } | ||
81 | |||
82 | static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | ||
83 | unsigned int value) | ||
84 | { | ||
85 | u16 data; | ||
86 | |||
87 | data = cpu_to_be16((reg << 12) | (value & 0xffffff)); | ||
88 | |||
89 | return do_hw_write(codec, reg, value, &data, 2); | ||
90 | } | ||
91 | |||
92 | static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | ||
93 | unsigned int value) | ||
94 | { | ||
95 | u16 data; | ||
96 | |||
97 | data = cpu_to_be16((reg << 9) | (value & 0x1ff)); | ||
98 | |||
99 | return do_hw_write(codec, reg, value, &data, 2); | ||
100 | } | ||
101 | |||
102 | static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
103 | unsigned int value) | ||
104 | { | ||
105 | u8 data[2]; | ||
106 | |||
107 | reg &= 0xff; | ||
108 | data[0] = reg; | ||
109 | data[1] = value & 0xff; | ||
110 | |||
111 | return do_hw_write(codec, reg, value, data, 2); | ||
112 | } | ||
113 | |||
114 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | ||
115 | unsigned int value) | ||
116 | { | ||
117 | u8 data[3]; | ||
118 | u16 val = cpu_to_be16(value); | ||
119 | |||
120 | data[0] = reg; | ||
121 | memcpy(&data[1], &val, sizeof(val)); | ||
122 | |||
123 | return do_hw_write(codec, reg, value, data, 3); | ||
124 | } | ||
125 | |||
126 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
127 | static unsigned int do_i2c_read(struct snd_soc_codec *codec, | ||
128 | void *reg, int reglen, | ||
129 | void *data, int datalen) | ||
130 | { | ||
131 | struct i2c_msg xfer[2]; | ||
132 | int ret; | ||
133 | struct i2c_client *client = codec->control_data; | ||
134 | |||
135 | /* Write register */ | ||
136 | xfer[0].addr = client->addr; | ||
137 | xfer[0].flags = 0; | ||
138 | xfer[0].len = reglen; | ||
139 | xfer[0].buf = reg; | ||
140 | |||
141 | /* Read data */ | ||
142 | xfer[1].addr = client->addr; | ||
143 | xfer[1].flags = I2C_M_RD; | ||
144 | xfer[1].len = datalen; | ||
145 | xfer[1].buf = data; | ||
146 | |||
147 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
148 | if (ret == 2) | ||
149 | return 0; | ||
150 | else if (ret < 0) | ||
151 | return ret; | ||
152 | else | ||
153 | return -EIO; | ||
154 | } | ||
155 | #endif | ||
156 | |||
157 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
158 | static unsigned int snd_soc_8_8_read_i2c(struct snd_soc_codec *codec, | ||
159 | unsigned int r) | ||
160 | { | ||
161 | u8 reg = r; | ||
162 | u8 data; | ||
163 | int ret; | ||
164 | |||
165 | ret = do_i2c_read(codec, ®, 1, &data, 1); | ||
166 | if (ret < 0) | ||
167 | return 0; | ||
168 | return data; | ||
169 | } | ||
170 | #else | ||
171 | #define snd_soc_8_8_read_i2c NULL | ||
172 | #endif | ||
173 | |||
174 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
175 | static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, | ||
176 | unsigned int r) | ||
177 | { | ||
178 | u8 reg = r; | ||
179 | u16 data; | ||
180 | int ret; | ||
181 | |||
182 | ret = do_i2c_read(codec, ®, 1, &data, 2); | ||
183 | if (ret < 0) | ||
184 | return 0; | ||
185 | return (data >> 8) | ((data & 0xff) << 8); | ||
186 | } | ||
187 | #else | ||
188 | #define snd_soc_8_16_read_i2c NULL | ||
189 | #endif | ||
190 | |||
191 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
192 | static unsigned int snd_soc_16_8_read_i2c(struct snd_soc_codec *codec, | ||
193 | unsigned int r) | ||
194 | { | ||
195 | u16 reg = r; | ||
196 | u8 data; | ||
197 | int ret; | ||
198 | |||
199 | ret = do_i2c_read(codec, ®, 2, &data, 1); | ||
200 | if (ret < 0) | ||
201 | return 0; | ||
202 | return data; | ||
203 | } | ||
204 | #else | ||
205 | #define snd_soc_16_8_read_i2c NULL | ||
206 | #endif | ||
207 | |||
208 | static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
209 | unsigned int value) | ||
210 | { | ||
211 | u8 data[3]; | ||
212 | u16 rval = cpu_to_be16(reg); | ||
213 | |||
214 | memcpy(data, &rval, sizeof(rval)); | ||
215 | data[2] = value; | ||
216 | |||
217 | return do_hw_write(codec, reg, value, data, 3); | ||
218 | } | ||
219 | |||
220 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
221 | static unsigned int snd_soc_16_16_read_i2c(struct snd_soc_codec *codec, | ||
222 | unsigned int r) | ||
223 | { | ||
224 | u16 reg = cpu_to_be16(r); | ||
225 | u16 data; | ||
226 | int ret; | ||
227 | |||
228 | ret = do_i2c_read(codec, ®, 2, &data, 2); | ||
229 | if (ret < 0) | ||
230 | return 0; | ||
231 | return be16_to_cpu(data); | ||
232 | } | ||
233 | #else | ||
234 | #define snd_soc_16_16_read_i2c NULL | ||
235 | #endif | ||
236 | |||
237 | static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, | ||
238 | unsigned int value) | ||
239 | { | ||
240 | u16 data[2]; | ||
241 | |||
242 | data[0] = cpu_to_be16(reg); | ||
243 | data[1] = cpu_to_be16(value); | ||
244 | |||
245 | return do_hw_write(codec, reg, value, data, sizeof(data)); | ||
246 | } | ||
247 | |||
248 | /* Primitive bulk write support for soc-cache. The data pointed to by | ||
249 | * `data' needs to already be in the form the hardware expects | ||
250 | * including any leading register specific data. Any data written | ||
251 | * through this function will not go through the cache as it only | ||
252 | * handles writing to volatile or out of bounds registers. | ||
253 | */ | ||
254 | static int snd_soc_hw_bulk_write_raw(struct snd_soc_codec *codec, unsigned int reg, | ||
255 | const void *data, size_t len) | ||
256 | { | ||
257 | int ret; | ||
258 | |||
259 | /* To ensure that we don't get out of sync with the cache, check | ||
260 | * whether the base register is volatile or if we've directly asked | ||
261 | * to bypass the cache. Out of bounds registers are considered | ||
262 | * volatile. | ||
263 | */ | ||
264 | if (!codec->cache_bypass | ||
265 | && !snd_soc_codec_volatile_register(codec, reg) | ||
266 | && reg < codec->driver->reg_cache_size) | ||
267 | return -EINVAL; | ||
268 | |||
269 | switch (codec->control_type) { | ||
270 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
271 | case SND_SOC_I2C: | ||
272 | ret = i2c_master_send(to_i2c_client(codec->dev), data, len); | ||
273 | break; | ||
274 | #endif | ||
275 | #if defined(CONFIG_SPI_MASTER) | ||
276 | case SND_SOC_SPI: | ||
277 | ret = spi_write(to_spi_device(codec->dev), data, len); | ||
278 | break; | ||
279 | #endif | ||
280 | default: | ||
281 | BUG(); | ||
282 | } | ||
283 | |||
284 | if (ret == len) | ||
285 | return 0; | ||
286 | if (ret < 0) | ||
287 | return ret; | ||
288 | else | ||
289 | return -EIO; | ||
290 | } | ||
291 | |||
292 | static struct { | ||
293 | int addr_bits; | ||
294 | int data_bits; | ||
295 | int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); | ||
296 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | ||
297 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | ||
298 | } io_types[] = { | ||
299 | { | ||
300 | .addr_bits = 4, .data_bits = 12, | ||
301 | .write = snd_soc_4_12_write, | ||
302 | }, | ||
303 | { | ||
304 | .addr_bits = 7, .data_bits = 9, | ||
305 | .write = snd_soc_7_9_write, | ||
306 | }, | ||
307 | { | ||
308 | .addr_bits = 8, .data_bits = 8, | ||
309 | .write = snd_soc_8_8_write, | ||
310 | .i2c_read = snd_soc_8_8_read_i2c, | ||
311 | }, | ||
312 | { | ||
313 | .addr_bits = 8, .data_bits = 16, | ||
314 | .write = snd_soc_8_16_write, | ||
315 | .i2c_read = snd_soc_8_16_read_i2c, | ||
316 | }, | ||
317 | { | ||
318 | .addr_bits = 16, .data_bits = 8, | ||
319 | .write = snd_soc_16_8_write, | ||
320 | .i2c_read = snd_soc_16_8_read_i2c, | ||
321 | }, | ||
322 | { | ||
323 | .addr_bits = 16, .data_bits = 16, | ||
324 | .write = snd_soc_16_16_write, | ||
325 | .i2c_read = snd_soc_16_16_read_i2c, | ||
326 | }, | ||
327 | }; | ||
328 | |||
329 | /** | ||
330 | * snd_soc_codec_set_cache_io: Set up standard I/O functions. | ||
331 | * | ||
332 | * @codec: CODEC to configure. | ||
333 | * @addr_bits: Number of bits of register address data. | ||
334 | * @data_bits: Number of bits of data per register. | ||
335 | * @control: Control bus used. | ||
336 | * | ||
337 | * Register formats are frequently shared between many I2C and SPI | ||
338 | * devices. In order to promote code reuse the ASoC core provides | ||
339 | * some standard implementations of CODEC read and write operations | ||
340 | * which can be set up using this function. | ||
341 | * | ||
342 | * The caller is responsible for allocating and initialising the | ||
343 | * actual cache. | ||
344 | * | ||
345 | * Note that at present this code cannot be used by CODECs with | ||
346 | * volatile registers. | ||
347 | */ | ||
348 | int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | ||
349 | int addr_bits, int data_bits, | ||
350 | enum snd_soc_control_type control) | ||
351 | { | ||
352 | int i; | ||
353 | |||
354 | for (i = 0; i < ARRAY_SIZE(io_types); i++) | ||
355 | if (io_types[i].addr_bits == addr_bits && | ||
356 | io_types[i].data_bits == data_bits) | ||
357 | break; | ||
358 | if (i == ARRAY_SIZE(io_types)) { | ||
359 | printk(KERN_ERR | ||
360 | "No I/O functions for %d bit address %d bit data\n", | ||
361 | addr_bits, data_bits); | ||
362 | return -EINVAL; | ||
363 | } | ||
364 | |||
365 | codec->write = io_types[i].write; | ||
366 | codec->read = hw_read; | ||
367 | codec->bulk_write_raw = snd_soc_hw_bulk_write_raw; | ||
368 | |||
369 | switch (control) { | ||
370 | case SND_SOC_I2C: | ||
371 | #if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) | ||
372 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
373 | #endif | ||
374 | if (io_types[i].i2c_read) | ||
375 | codec->hw_read = io_types[i].i2c_read; | ||
376 | |||
377 | codec->control_data = container_of(codec->dev, | ||
378 | struct i2c_client, | ||
379 | dev); | ||
380 | break; | ||
381 | |||
382 | case SND_SOC_SPI: | ||
383 | #ifdef CONFIG_SPI_MASTER | ||
384 | codec->hw_write = do_spi_write; | ||
385 | #endif | ||
386 | |||
387 | codec->control_data = container_of(codec->dev, | ||
388 | struct spi_device, | ||
389 | dev); | ||
390 | break; | ||
391 | } | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | ||
396 | |||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c new file mode 100644 index 000000000000..b5759397afa3 --- /dev/null +++ b/sound/soc/soc-pcm.c | |||
@@ -0,0 +1,639 @@ | |||
1 | /* | ||
2 | * soc-pcm.c -- ALSA SoC PCM | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * Copyright (C) 2010 Slimlogic Ltd. | ||
7 | * Copyright (C) 2010 Texas Instruments Inc. | ||
8 | * | ||
9 | * Authors: Liam Girdwood <lrg@ti.com> | ||
10 | * Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/initval.h> | ||
29 | |||
30 | static DEFINE_MUTEX(pcm_mutex); | ||
31 | |||
32 | static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) | ||
33 | { | ||
34 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
35 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
36 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
37 | int ret; | ||
38 | |||
39 | if (!codec_dai->driver->symmetric_rates && | ||
40 | !cpu_dai->driver->symmetric_rates && | ||
41 | !rtd->dai_link->symmetric_rates) | ||
42 | return 0; | ||
43 | |||
44 | /* This can happen if multiple streams are starting simultaneously - | ||
45 | * the second can need to get its constraints before the first has | ||
46 | * picked a rate. Complain and allow the application to carry on. | ||
47 | */ | ||
48 | if (!rtd->rate) { | ||
49 | dev_warn(&rtd->dev, | ||
50 | "Not enforcing symmetric_rates due to race\n"); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate); | ||
55 | |||
56 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, | ||
57 | SNDRV_PCM_HW_PARAM_RATE, | ||
58 | rtd->rate, rtd->rate); | ||
59 | if (ret < 0) { | ||
60 | dev_err(&rtd->dev, | ||
61 | "Unable to apply rate symmetry constraint: %d\n", ret); | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Called by ALSA when a PCM substream is opened, the runtime->hw record is | ||
70 | * then initialized and any private data can be allocated. This also calls | ||
71 | * startup for the cpu DAI, platform, machine and codec DAI. | ||
72 | */ | ||
73 | static int soc_pcm_open(struct snd_pcm_substream *substream) | ||
74 | { | ||
75 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
76 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
77 | struct snd_soc_platform *platform = rtd->platform; | ||
78 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
79 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
80 | struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver; | ||
81 | struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver; | ||
82 | int ret = 0; | ||
83 | |||
84 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | ||
85 | |||
86 | /* startup the audio subsystem */ | ||
87 | if (cpu_dai->driver->ops->startup) { | ||
88 | ret = cpu_dai->driver->ops->startup(substream, cpu_dai); | ||
89 | if (ret < 0) { | ||
90 | printk(KERN_ERR "asoc: can't open interface %s\n", | ||
91 | cpu_dai->name); | ||
92 | goto out; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | if (platform->driver->ops && platform->driver->ops->open) { | ||
97 | ret = platform->driver->ops->open(substream); | ||
98 | if (ret < 0) { | ||
99 | printk(KERN_ERR "asoc: can't open platform %s\n", platform->name); | ||
100 | goto platform_err; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | if (codec_dai->driver->ops->startup) { | ||
105 | ret = codec_dai->driver->ops->startup(substream, codec_dai); | ||
106 | if (ret < 0) { | ||
107 | printk(KERN_ERR "asoc: can't open codec %s\n", | ||
108 | codec_dai->name); | ||
109 | goto codec_dai_err; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | if (rtd->dai_link->ops && rtd->dai_link->ops->startup) { | ||
114 | ret = rtd->dai_link->ops->startup(substream); | ||
115 | if (ret < 0) { | ||
116 | printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name); | ||
117 | goto machine_err; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /* Check that the codec and cpu DAIs are compatible */ | ||
122 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
123 | runtime->hw.rate_min = | ||
124 | max(codec_dai_drv->playback.rate_min, | ||
125 | cpu_dai_drv->playback.rate_min); | ||
126 | runtime->hw.rate_max = | ||
127 | min(codec_dai_drv->playback.rate_max, | ||
128 | cpu_dai_drv->playback.rate_max); | ||
129 | runtime->hw.channels_min = | ||
130 | max(codec_dai_drv->playback.channels_min, | ||
131 | cpu_dai_drv->playback.channels_min); | ||
132 | runtime->hw.channels_max = | ||
133 | min(codec_dai_drv->playback.channels_max, | ||
134 | cpu_dai_drv->playback.channels_max); | ||
135 | runtime->hw.formats = | ||
136 | codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats; | ||
137 | runtime->hw.rates = | ||
138 | codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates; | ||
139 | if (codec_dai_drv->playback.rates | ||
140 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
141 | runtime->hw.rates |= cpu_dai_drv->playback.rates; | ||
142 | if (cpu_dai_drv->playback.rates | ||
143 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
144 | runtime->hw.rates |= codec_dai_drv->playback.rates; | ||
145 | } else { | ||
146 | runtime->hw.rate_min = | ||
147 | max(codec_dai_drv->capture.rate_min, | ||
148 | cpu_dai_drv->capture.rate_min); | ||
149 | runtime->hw.rate_max = | ||
150 | min(codec_dai_drv->capture.rate_max, | ||
151 | cpu_dai_drv->capture.rate_max); | ||
152 | runtime->hw.channels_min = | ||
153 | max(codec_dai_drv->capture.channels_min, | ||
154 | cpu_dai_drv->capture.channels_min); | ||
155 | runtime->hw.channels_max = | ||
156 | min(codec_dai_drv->capture.channels_max, | ||
157 | cpu_dai_drv->capture.channels_max); | ||
158 | runtime->hw.formats = | ||
159 | codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats; | ||
160 | runtime->hw.rates = | ||
161 | codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates; | ||
162 | if (codec_dai_drv->capture.rates | ||
163 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
164 | runtime->hw.rates |= cpu_dai_drv->capture.rates; | ||
165 | if (cpu_dai_drv->capture.rates | ||
166 | & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS)) | ||
167 | runtime->hw.rates |= codec_dai_drv->capture.rates; | ||
168 | } | ||
169 | |||
170 | ret = -EINVAL; | ||
171 | snd_pcm_limit_hw_rates(runtime); | ||
172 | if (!runtime->hw.rates) { | ||
173 | printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", | ||
174 | codec_dai->name, cpu_dai->name); | ||
175 | goto config_err; | ||
176 | } | ||
177 | if (!runtime->hw.formats) { | ||
178 | printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", | ||
179 | codec_dai->name, cpu_dai->name); | ||
180 | goto config_err; | ||
181 | } | ||
182 | if (!runtime->hw.channels_min || !runtime->hw.channels_max || | ||
183 | runtime->hw.channels_min > runtime->hw.channels_max) { | ||
184 | printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", | ||
185 | codec_dai->name, cpu_dai->name); | ||
186 | goto config_err; | ||
187 | } | ||
188 | |||
189 | /* Symmetry only applies if we've already got an active stream. */ | ||
190 | if (cpu_dai->active || codec_dai->active) { | ||
191 | ret = soc_pcm_apply_symmetry(substream); | ||
192 | if (ret != 0) | ||
193 | goto config_err; | ||
194 | } | ||
195 | |||
196 | pr_debug("asoc: %s <-> %s info:\n", | ||
197 | codec_dai->name, cpu_dai->name); | ||
198 | pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates); | ||
199 | pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min, | ||
200 | runtime->hw.channels_max); | ||
201 | pr_debug("asoc: min rate %d max rate %d\n", runtime->hw.rate_min, | ||
202 | runtime->hw.rate_max); | ||
203 | |||
204 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
205 | cpu_dai->playback_active++; | ||
206 | codec_dai->playback_active++; | ||
207 | } else { | ||
208 | cpu_dai->capture_active++; | ||
209 | codec_dai->capture_active++; | ||
210 | } | ||
211 | cpu_dai->active++; | ||
212 | codec_dai->active++; | ||
213 | rtd->codec->active++; | ||
214 | mutex_unlock(&rtd->pcm_mutex); | ||
215 | return 0; | ||
216 | |||
217 | config_err: | ||
218 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | ||
219 | rtd->dai_link->ops->shutdown(substream); | ||
220 | |||
221 | machine_err: | ||
222 | if (codec_dai->driver->ops->shutdown) | ||
223 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
224 | |||
225 | codec_dai_err: | ||
226 | if (platform->driver->ops && platform->driver->ops->close) | ||
227 | platform->driver->ops->close(substream); | ||
228 | |||
229 | platform_err: | ||
230 | if (cpu_dai->driver->ops->shutdown) | ||
231 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | ||
232 | out: | ||
233 | mutex_unlock(&rtd->pcm_mutex); | ||
234 | return ret; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Power down the audio subsystem pmdown_time msecs after close is called. | ||
239 | * This is to ensure there are no pops or clicks in between any music tracks | ||
240 | * due to DAPM power cycling. | ||
241 | */ | ||
242 | static void close_delayed_work(struct work_struct *work) | ||
243 | { | ||
244 | struct snd_soc_pcm_runtime *rtd = | ||
245 | container_of(work, struct snd_soc_pcm_runtime, delayed_work.work); | ||
246 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
247 | |||
248 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | ||
249 | |||
250 | pr_debug("pop wq checking: %s status: %s waiting: %s\n", | ||
251 | codec_dai->driver->playback.stream_name, | ||
252 | codec_dai->playback_active ? "active" : "inactive", | ||
253 | codec_dai->pop_wait ? "yes" : "no"); | ||
254 | |||
255 | /* are we waiting on this codec DAI stream */ | ||
256 | if (codec_dai->pop_wait == 1) { | ||
257 | codec_dai->pop_wait = 0; | ||
258 | snd_soc_dapm_stream_event(rtd, | ||
259 | codec_dai->driver->playback.stream_name, | ||
260 | SND_SOC_DAPM_STREAM_STOP); | ||
261 | } | ||
262 | |||
263 | mutex_unlock(&rtd->pcm_mutex); | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * Called by ALSA when a PCM substream is closed. Private data can be | ||
268 | * freed here. The cpu DAI, codec DAI, machine and platform are also | ||
269 | * shutdown. | ||
270 | */ | ||
271 | static int soc_pcm_close(struct snd_pcm_substream *substream) | ||
272 | { | ||
273 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
274 | struct snd_soc_platform *platform = rtd->platform; | ||
275 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
276 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
277 | struct snd_soc_codec *codec = rtd->codec; | ||
278 | |||
279 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | ||
280 | |||
281 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
282 | cpu_dai->playback_active--; | ||
283 | codec_dai->playback_active--; | ||
284 | } else { | ||
285 | cpu_dai->capture_active--; | ||
286 | codec_dai->capture_active--; | ||
287 | } | ||
288 | |||
289 | cpu_dai->active--; | ||
290 | codec_dai->active--; | ||
291 | codec->active--; | ||
292 | |||
293 | /* Muting the DAC suppresses artifacts caused during digital | ||
294 | * shutdown, for example from stopping clocks. | ||
295 | */ | ||
296 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
297 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
298 | |||
299 | if (cpu_dai->driver->ops->shutdown) | ||
300 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | ||
301 | |||
302 | if (codec_dai->driver->ops->shutdown) | ||
303 | codec_dai->driver->ops->shutdown(substream, codec_dai); | ||
304 | |||
305 | if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown) | ||
306 | rtd->dai_link->ops->shutdown(substream); | ||
307 | |||
308 | if (platform->driver->ops && platform->driver->ops->close) | ||
309 | platform->driver->ops->close(substream); | ||
310 | cpu_dai->runtime = NULL; | ||
311 | |||
312 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
313 | /* start delayed pop wq here for playback streams */ | ||
314 | codec_dai->pop_wait = 1; | ||
315 | schedule_delayed_work(&rtd->delayed_work, | ||
316 | msecs_to_jiffies(rtd->pmdown_time)); | ||
317 | } else { | ||
318 | /* capture streams can be powered down now */ | ||
319 | snd_soc_dapm_stream_event(rtd, | ||
320 | codec_dai->driver->capture.stream_name, | ||
321 | SND_SOC_DAPM_STREAM_STOP); | ||
322 | } | ||
323 | |||
324 | mutex_unlock(&rtd->pcm_mutex); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | /* | ||
329 | * Called by ALSA when the PCM substream is prepared, can set format, sample | ||
330 | * rate, etc. This function is non atomic and can be called multiple times, | ||
331 | * it can refer to the runtime info. | ||
332 | */ | ||
333 | static int soc_pcm_prepare(struct snd_pcm_substream *substream) | ||
334 | { | ||
335 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
336 | struct snd_soc_platform *platform = rtd->platform; | ||
337 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
338 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
339 | int ret = 0; | ||
340 | |||
341 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | ||
342 | |||
343 | if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) { | ||
344 | ret = rtd->dai_link->ops->prepare(substream); | ||
345 | if (ret < 0) { | ||
346 | printk(KERN_ERR "asoc: machine prepare error\n"); | ||
347 | goto out; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | if (platform->driver->ops && platform->driver->ops->prepare) { | ||
352 | ret = platform->driver->ops->prepare(substream); | ||
353 | if (ret < 0) { | ||
354 | printk(KERN_ERR "asoc: platform prepare error\n"); | ||
355 | goto out; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | if (codec_dai->driver->ops->prepare) { | ||
360 | ret = codec_dai->driver->ops->prepare(substream, codec_dai); | ||
361 | if (ret < 0) { | ||
362 | printk(KERN_ERR "asoc: codec DAI prepare error\n"); | ||
363 | goto out; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | if (cpu_dai->driver->ops->prepare) { | ||
368 | ret = cpu_dai->driver->ops->prepare(substream, cpu_dai); | ||
369 | if (ret < 0) { | ||
370 | printk(KERN_ERR "asoc: cpu DAI prepare error\n"); | ||
371 | goto out; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* cancel any delayed stream shutdown that is pending */ | ||
376 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
377 | codec_dai->pop_wait) { | ||
378 | codec_dai->pop_wait = 0; | ||
379 | cancel_delayed_work(&rtd->delayed_work); | ||
380 | } | ||
381 | |||
382 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
383 | snd_soc_dapm_stream_event(rtd, | ||
384 | codec_dai->driver->playback.stream_name, | ||
385 | SND_SOC_DAPM_STREAM_START); | ||
386 | else | ||
387 | snd_soc_dapm_stream_event(rtd, | ||
388 | codec_dai->driver->capture.stream_name, | ||
389 | SND_SOC_DAPM_STREAM_START); | ||
390 | |||
391 | snd_soc_dai_digital_mute(codec_dai, 0); | ||
392 | |||
393 | out: | ||
394 | mutex_unlock(&rtd->pcm_mutex); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | /* | ||
399 | * Called by ALSA when the hardware params are set by application. This | ||
400 | * function can also be called multiple times and can allocate buffers | ||
401 | * (using snd_pcm_lib_* ). It's non-atomic. | ||
402 | */ | ||
403 | static int soc_pcm_hw_params(struct snd_pcm_substream *substream, | ||
404 | struct snd_pcm_hw_params *params) | ||
405 | { | ||
406 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
407 | struct snd_soc_platform *platform = rtd->platform; | ||
408 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
409 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
410 | int ret = 0; | ||
411 | |||
412 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | ||
413 | |||
414 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) { | ||
415 | ret = rtd->dai_link->ops->hw_params(substream, params); | ||
416 | if (ret < 0) { | ||
417 | printk(KERN_ERR "asoc: machine hw_params failed\n"); | ||
418 | goto out; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | if (codec_dai->driver->ops->hw_params) { | ||
423 | ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); | ||
424 | if (ret < 0) { | ||
425 | printk(KERN_ERR "asoc: can't set codec %s hw params\n", | ||
426 | codec_dai->name); | ||
427 | goto codec_err; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | if (cpu_dai->driver->ops->hw_params) { | ||
432 | ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai); | ||
433 | if (ret < 0) { | ||
434 | printk(KERN_ERR "asoc: interface %s hw params failed\n", | ||
435 | cpu_dai->name); | ||
436 | goto interface_err; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | if (platform->driver->ops && platform->driver->ops->hw_params) { | ||
441 | ret = platform->driver->ops->hw_params(substream, params); | ||
442 | if (ret < 0) { | ||
443 | printk(KERN_ERR "asoc: platform %s hw params failed\n", | ||
444 | platform->name); | ||
445 | goto platform_err; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | rtd->rate = params_rate(params); | ||
450 | |||
451 | out: | ||
452 | mutex_unlock(&rtd->pcm_mutex); | ||
453 | return ret; | ||
454 | |||
455 | platform_err: | ||
456 | if (cpu_dai->driver->ops->hw_free) | ||
457 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | ||
458 | |||
459 | interface_err: | ||
460 | if (codec_dai->driver->ops->hw_free) | ||
461 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
462 | |||
463 | codec_err: | ||
464 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | ||
465 | rtd->dai_link->ops->hw_free(substream); | ||
466 | |||
467 | mutex_unlock(&rtd->pcm_mutex); | ||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * Frees resources allocated by hw_params, can be called multiple times | ||
473 | */ | ||
474 | static int soc_pcm_hw_free(struct snd_pcm_substream *substream) | ||
475 | { | ||
476 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
477 | struct snd_soc_platform *platform = rtd->platform; | ||
478 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
479 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
480 | struct snd_soc_codec *codec = rtd->codec; | ||
481 | |||
482 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | ||
483 | |||
484 | /* apply codec digital mute */ | ||
485 | if (!codec->active) | ||
486 | snd_soc_dai_digital_mute(codec_dai, 1); | ||
487 | |||
488 | /* free any machine hw params */ | ||
489 | if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free) | ||
490 | rtd->dai_link->ops->hw_free(substream); | ||
491 | |||
492 | /* free any DMA resources */ | ||
493 | if (platform->driver->ops && platform->driver->ops->hw_free) | ||
494 | platform->driver->ops->hw_free(substream); | ||
495 | |||
496 | /* now free hw params for the DAIs */ | ||
497 | if (codec_dai->driver->ops->hw_free) | ||
498 | codec_dai->driver->ops->hw_free(substream, codec_dai); | ||
499 | |||
500 | if (cpu_dai->driver->ops->hw_free) | ||
501 | cpu_dai->driver->ops->hw_free(substream, cpu_dai); | ||
502 | |||
503 | mutex_unlock(&rtd->pcm_mutex); | ||
504 | return 0; | ||
505 | } | ||
506 | |||
507 | static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
508 | { | ||
509 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
510 | struct snd_soc_platform *platform = rtd->platform; | ||
511 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
512 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
513 | int ret; | ||
514 | |||
515 | if (codec_dai->driver->ops->trigger) { | ||
516 | ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai); | ||
517 | if (ret < 0) | ||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | if (platform->driver->ops && platform->driver->ops->trigger) { | ||
522 | ret = platform->driver->ops->trigger(substream, cmd); | ||
523 | if (ret < 0) | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | if (cpu_dai->driver->ops->trigger) { | ||
528 | ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai); | ||
529 | if (ret < 0) | ||
530 | return ret; | ||
531 | } | ||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * soc level wrapper for pointer callback | ||
537 | * If cpu_dai, codec_dai, platform driver has the delay callback, than | ||
538 | * the runtime->delay will be updated accordingly. | ||
539 | */ | ||
540 | static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream) | ||
541 | { | ||
542 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
543 | struct snd_soc_platform *platform = rtd->platform; | ||
544 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
545 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
546 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
547 | snd_pcm_uframes_t offset = 0; | ||
548 | snd_pcm_sframes_t delay = 0; | ||
549 | |||
550 | if (platform->driver->ops && platform->driver->ops->pointer) | ||
551 | offset = platform->driver->ops->pointer(substream); | ||
552 | |||
553 | if (cpu_dai->driver->ops->delay) | ||
554 | delay += cpu_dai->driver->ops->delay(substream, cpu_dai); | ||
555 | |||
556 | if (codec_dai->driver->ops->delay) | ||
557 | delay += codec_dai->driver->ops->delay(substream, codec_dai); | ||
558 | |||
559 | if (platform->driver->delay) | ||
560 | delay += platform->driver->delay(substream, codec_dai); | ||
561 | |||
562 | runtime->delay = delay; | ||
563 | |||
564 | return offset; | ||
565 | } | ||
566 | |||
567 | /* ASoC PCM operations */ | ||
568 | static struct snd_pcm_ops soc_pcm_ops = { | ||
569 | .open = soc_pcm_open, | ||
570 | .close = soc_pcm_close, | ||
571 | .hw_params = soc_pcm_hw_params, | ||
572 | .hw_free = soc_pcm_hw_free, | ||
573 | .prepare = soc_pcm_prepare, | ||
574 | .trigger = soc_pcm_trigger, | ||
575 | .pointer = soc_pcm_pointer, | ||
576 | }; | ||
577 | |||
578 | /* create a new pcm */ | ||
579 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | ||
580 | { | ||
581 | struct snd_soc_codec *codec = rtd->codec; | ||
582 | struct snd_soc_platform *platform = rtd->platform; | ||
583 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
584 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
585 | struct snd_pcm *pcm; | ||
586 | char new_name[64]; | ||
587 | int ret = 0, playback = 0, capture = 0; | ||
588 | |||
589 | /* check client and interface hw capabilities */ | ||
590 | snprintf(new_name, sizeof(new_name), "%s %s-%d", | ||
591 | rtd->dai_link->stream_name, codec_dai->name, num); | ||
592 | |||
593 | if (codec_dai->driver->playback.channels_min) | ||
594 | playback = 1; | ||
595 | if (codec_dai->driver->capture.channels_min) | ||
596 | capture = 1; | ||
597 | |||
598 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name); | ||
599 | ret = snd_pcm_new(rtd->card->snd_card, new_name, | ||
600 | num, playback, capture, &pcm); | ||
601 | if (ret < 0) { | ||
602 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | /* DAPM dai link stream work */ | ||
607 | INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work); | ||
608 | |||
609 | rtd->pcm = pcm; | ||
610 | pcm->private_data = rtd; | ||
611 | if (platform->driver->ops) { | ||
612 | soc_pcm_ops.mmap = platform->driver->ops->mmap; | ||
613 | soc_pcm_ops.pointer = platform->driver->ops->pointer; | ||
614 | soc_pcm_ops.ioctl = platform->driver->ops->ioctl; | ||
615 | soc_pcm_ops.copy = platform->driver->ops->copy; | ||
616 | soc_pcm_ops.silence = platform->driver->ops->silence; | ||
617 | soc_pcm_ops.ack = platform->driver->ops->ack; | ||
618 | soc_pcm_ops.page = platform->driver->ops->page; | ||
619 | } | ||
620 | |||
621 | if (playback) | ||
622 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops); | ||
623 | |||
624 | if (capture) | ||
625 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops); | ||
626 | |||
627 | if (platform->driver->pcm_new) { | ||
628 | ret = platform->driver->pcm_new(rtd); | ||
629 | if (ret < 0) { | ||
630 | pr_err("asoc: platform pcm constructor failed\n"); | ||
631 | return ret; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | pcm->private_free = platform->driver->pcm_free; | ||
636 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | ||
637 | cpu_dai->name); | ||
638 | return ret; | ||
639 | } | ||
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 035d39a4beb4..c6af1fd707f5 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -12,6 +12,15 @@ config SND_SOC_TEGRA_I2S | |||
12 | Tegra I2S interface. You will also need to select the individual | 12 | Tegra I2S interface. You will also need to select the individual |
13 | machine drivers to support below. | 13 | machine drivers to support below. |
14 | 14 | ||
15 | config SND_SOC_TEGRA_SPDIF | ||
16 | tristate | ||
17 | depends on SND_SOC_TEGRA | ||
18 | default m | ||
19 | help | ||
20 | Say Y or M if you want to add support for the SPDIF interface. | ||
21 | You will also need to select the individual machine drivers to support | ||
22 | below. | ||
23 | |||
15 | config MACH_HAS_SND_SOC_TEGRA_WM8903 | 24 | config MACH_HAS_SND_SOC_TEGRA_WM8903 |
16 | bool | 25 | bool |
17 | help | 26 | help |
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index fa6574d92a31..4d943b3fe150 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile | |||
@@ -2,12 +2,14 @@ | |||
2 | snd-soc-tegra-das-objs := tegra_das.o | 2 | snd-soc-tegra-das-objs := tegra_das.o |
3 | snd-soc-tegra-pcm-objs := tegra_pcm.o | 3 | snd-soc-tegra-pcm-objs := tegra_pcm.o |
4 | snd-soc-tegra-i2s-objs := tegra_i2s.o | 4 | snd-soc-tegra-i2s-objs := tegra_i2s.o |
5 | snd-soc-tegra-spdif-objs := tegra_spdif.o | ||
5 | snd-soc-tegra-utils-objs += tegra_asoc_utils.o | 6 | snd-soc-tegra-utils-objs += tegra_asoc_utils.o |
6 | 7 | ||
7 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o | 8 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-utils.o |
8 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o | 9 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-das.o |
9 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o | 10 | obj-$(CONFIG_SND_SOC_TEGRA) += snd-soc-tegra-pcm.o |
10 | obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o | 11 | obj-$(CONFIG_SND_SOC_TEGRA_I2S) += snd-soc-tegra-i2s.o |
12 | obj-$(CONFIG_SND_SOC_TEGRA_SPDIF) += snd-soc-tegra-spdif.o | ||
11 | 13 | ||
12 | # Tegra machine Support | 14 | # Tegra machine Support |
13 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o | 15 | snd-soc-tegra-wm8903-objs := tegra_wm8903.o |
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c index 95f03c10b4f7..f36b9969cfec 100644 --- a/sound/soc/tegra/tegra_i2s.c +++ b/sound/soc/tegra/tegra_i2s.c | |||
@@ -354,7 +354,6 @@ struct snd_soc_dai_driver tegra_i2s_dai[] = { | |||
354 | static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) | 354 | static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) |
355 | { | 355 | { |
356 | struct tegra_i2s * i2s; | 356 | struct tegra_i2s * i2s; |
357 | char clk_name[12]; /* tegra-i2s.0 */ | ||
358 | struct resource *mem, *memregion, *dmareq; | 357 | struct resource *mem, *memregion, *dmareq; |
359 | int ret; | 358 | int ret; |
360 | 359 | ||
@@ -389,8 +388,7 @@ static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) | |||
389 | } | 388 | } |
390 | dev_set_drvdata(&pdev->dev, i2s); | 389 | dev_set_drvdata(&pdev->dev, i2s); |
391 | 390 | ||
392 | snprintf(clk_name, sizeof(clk_name), DRV_NAME ".%d", pdev->id); | 391 | i2s->clk_i2s = clk_get(&pdev->dev, NULL); |
393 | i2s->clk_i2s = clk_get_sys(clk_name, NULL); | ||
394 | if (IS_ERR(i2s->clk_i2s)) { | 392 | if (IS_ERR(i2s->clk_i2s)) { |
395 | dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); | 393 | dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); |
396 | ret = PTR_ERR(i2s->clk_i2s); | 394 | ret = PTR_ERR(i2s->clk_i2s); |
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 3c271f953582..ff86e5e3db68 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c | |||
@@ -322,9 +322,11 @@ static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) | |||
322 | 322 | ||
323 | static u64 tegra_dma_mask = DMA_BIT_MASK(32); | 323 | static u64 tegra_dma_mask = DMA_BIT_MASK(32); |
324 | 324 | ||
325 | static int tegra_pcm_new(struct snd_card *card, | 325 | static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd) |
326 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
327 | { | 326 | { |
327 | struct snd_card *card = rtd->card->snd_card; | ||
328 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
329 | struct snd_pcm *pcm = rtd->pcm; | ||
328 | int ret = 0; | 330 | int ret = 0; |
329 | 331 | ||
330 | if (!card->dev->dma_mask) | 332 | if (!card->dev->dma_mask) |
diff --git a/sound/soc/tegra/tegra_spdif.c b/sound/soc/tegra/tegra_spdif.c new file mode 100644 index 000000000000..abe606b0a29e --- /dev/null +++ b/sound/soc/tegra/tegra_spdif.c | |||
@@ -0,0 +1,371 @@ | |||
1 | /* | ||
2 | * tegra_spdif.c - Tegra SPDIF driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
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 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/debugfs.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/seq_file.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/io.h> | ||
31 | #include <mach/iomap.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <sound/pcm_params.h> | ||
35 | #include <sound/soc.h> | ||
36 | |||
37 | #include "tegra_spdif.h" | ||
38 | |||
39 | #define DRV_NAME "tegra-spdif" | ||
40 | |||
41 | static inline void tegra_spdif_write(struct tegra_spdif *spdif, u32 reg, | ||
42 | u32 val) | ||
43 | { | ||
44 | __raw_writel(val, spdif->regs + reg); | ||
45 | } | ||
46 | |||
47 | static inline u32 tegra_spdif_read(struct tegra_spdif *spdif, u32 reg) | ||
48 | { | ||
49 | return __raw_readl(spdif->regs + reg); | ||
50 | } | ||
51 | |||
52 | #ifdef CONFIG_DEBUG_FS | ||
53 | static int tegra_spdif_show(struct seq_file *s, void *unused) | ||
54 | { | ||
55 | #define REG(r) { r, #r } | ||
56 | static const struct { | ||
57 | int offset; | ||
58 | const char *name; | ||
59 | } regs[] = { | ||
60 | REG(TEGRA_SPDIF_CTRL), | ||
61 | REG(TEGRA_SPDIF_STATUS), | ||
62 | REG(TEGRA_SPDIF_STROBE_CTRL), | ||
63 | REG(TEGRA_SPDIF_DATA_FIFO_CSR), | ||
64 | REG(TEGRA_SPDIF_CH_STA_RX_A), | ||
65 | REG(TEGRA_SPDIF_CH_STA_RX_B), | ||
66 | REG(TEGRA_SPDIF_CH_STA_RX_C), | ||
67 | REG(TEGRA_SPDIF_CH_STA_RX_D), | ||
68 | REG(TEGRA_SPDIF_CH_STA_RX_E), | ||
69 | REG(TEGRA_SPDIF_CH_STA_RX_F), | ||
70 | REG(TEGRA_SPDIF_CH_STA_TX_A), | ||
71 | REG(TEGRA_SPDIF_CH_STA_TX_B), | ||
72 | REG(TEGRA_SPDIF_CH_STA_TX_C), | ||
73 | REG(TEGRA_SPDIF_CH_STA_TX_D), | ||
74 | REG(TEGRA_SPDIF_CH_STA_TX_E), | ||
75 | REG(TEGRA_SPDIF_CH_STA_TX_F), | ||
76 | }; | ||
77 | #undef REG | ||
78 | |||
79 | struct tegra_spdif *spdif = s->private; | ||
80 | int i; | ||
81 | |||
82 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
83 | u32 val = tegra_spdif_read(spdif, regs[i].offset); | ||
84 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
85 | } | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int tegra_spdif_debug_open(struct inode *inode, struct file *file) | ||
91 | { | ||
92 | return single_open(file, tegra_spdif_show, inode->i_private); | ||
93 | } | ||
94 | |||
95 | static const struct file_operations tegra_spdif_debug_fops = { | ||
96 | .open = tegra_spdif_debug_open, | ||
97 | .read = seq_read, | ||
98 | .llseek = seq_lseek, | ||
99 | .release = single_release, | ||
100 | }; | ||
101 | |||
102 | static void tegra_spdif_debug_add(struct tegra_spdif *spdif) | ||
103 | { | ||
104 | spdif->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
105 | snd_soc_debugfs_root, spdif, | ||
106 | &tegra_spdif_debug_fops); | ||
107 | } | ||
108 | |||
109 | static void tegra_spdif_debug_remove(struct tegra_spdif *spdif) | ||
110 | { | ||
111 | if (spdif->debug) | ||
112 | debugfs_remove(spdif->debug); | ||
113 | } | ||
114 | #else | ||
115 | static inline void tegra_spdif_debug_add(struct tegra_spdif *spdif) | ||
116 | { | ||
117 | } | ||
118 | |||
119 | static inline void tegra_spdif_debug_remove(struct tegra_spdif *spdif) | ||
120 | { | ||
121 | } | ||
122 | #endif | ||
123 | |||
124 | static int tegra_spdif_hw_params(struct snd_pcm_substream *substream, | ||
125 | struct snd_pcm_hw_params *params, | ||
126 | struct snd_soc_dai *dai) | ||
127 | { | ||
128 | struct device *dev = substream->pcm->card->dev; | ||
129 | struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
130 | int ret, srate, spdifclock; | ||
131 | |||
132 | spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_PACK; | ||
133 | spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_BIT_MODE_MASK; | ||
134 | switch (params_format(params)) { | ||
135 | case SNDRV_PCM_FORMAT_S16_LE: | ||
136 | spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_PACK; | ||
137 | spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_BIT_MODE_16BIT; | ||
138 | break; | ||
139 | default: | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | |||
143 | srate = params_rate(params); | ||
144 | switch (params_rate(params)) { | ||
145 | case 32000: | ||
146 | spdifclock = 4096000; | ||
147 | break; | ||
148 | case 44100: | ||
149 | spdifclock = 5644800; | ||
150 | break; | ||
151 | case 48000: | ||
152 | spdifclock = 6144000; | ||
153 | break; | ||
154 | case 88200: | ||
155 | spdifclock = 11289600; | ||
156 | break; | ||
157 | case 96000: | ||
158 | spdifclock = 12288000; | ||
159 | break; | ||
160 | case 176400: | ||
161 | spdifclock = 22579200; | ||
162 | break; | ||
163 | case 192000: | ||
164 | spdifclock = 24576000; | ||
165 | break; | ||
166 | default: | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | ret = clk_set_rate(spdif->clk_spdif_out, spdifclock); | ||
171 | if (ret) { | ||
172 | dev_err(dev, "Can't set SPDIF clock rate: %d\n", ret); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static void tegra_spdif_start_playback(struct tegra_spdif *spdif) | ||
180 | { | ||
181 | spdif->reg_ctrl |= TEGRA_SPDIF_CTRL_TX_EN; | ||
182 | tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl); | ||
183 | } | ||
184 | |||
185 | static void tegra_spdif_stop_playback(struct tegra_spdif *spdif) | ||
186 | { | ||
187 | spdif->reg_ctrl &= ~TEGRA_SPDIF_CTRL_TX_EN; | ||
188 | tegra_spdif_write(spdif, TEGRA_SPDIF_CTRL, spdif->reg_ctrl); | ||
189 | } | ||
190 | |||
191 | static int tegra_spdif_trigger(struct snd_pcm_substream *substream, int cmd, | ||
192 | struct snd_soc_dai *dai) | ||
193 | { | ||
194 | struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
195 | |||
196 | switch (cmd) { | ||
197 | case SNDRV_PCM_TRIGGER_START: | ||
198 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
199 | case SNDRV_PCM_TRIGGER_RESUME: | ||
200 | if (!spdif->clk_refs) | ||
201 | clk_enable(spdif->clk_spdif_out); | ||
202 | spdif->clk_refs++; | ||
203 | tegra_spdif_start_playback(spdif); | ||
204 | break; | ||
205 | case SNDRV_PCM_TRIGGER_STOP: | ||
206 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
207 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
208 | tegra_spdif_stop_playback(spdif); | ||
209 | spdif->clk_refs--; | ||
210 | if (!spdif->clk_refs) | ||
211 | clk_disable(spdif->clk_spdif_out); | ||
212 | break; | ||
213 | default: | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int tegra_spdif_probe(struct snd_soc_dai *dai) | ||
221 | { | ||
222 | struct tegra_spdif *spdif = snd_soc_dai_get_drvdata(dai); | ||
223 | |||
224 | dai->capture_dma_data = NULL; | ||
225 | dai->playback_dma_data = &spdif->playback_dma_data; | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static struct snd_soc_dai_ops tegra_spdif_dai_ops = { | ||
231 | .hw_params = tegra_spdif_hw_params, | ||
232 | .trigger = tegra_spdif_trigger, | ||
233 | }; | ||
234 | |||
235 | struct snd_soc_dai_driver tegra_spdif_dai = { | ||
236 | .name = DRV_NAME, | ||
237 | .probe = tegra_spdif_probe, | ||
238 | .playback = { | ||
239 | .channels_min = 2, | ||
240 | .channels_max = 2, | ||
241 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
242 | SNDRV_PCM_RATE_48000, | ||
243 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
244 | }, | ||
245 | .ops = &tegra_spdif_dai_ops, | ||
246 | }; | ||
247 | |||
248 | static __devinit int tegra_spdif_platform_probe(struct platform_device *pdev) | ||
249 | { | ||
250 | struct tegra_spdif *spdif; | ||
251 | struct resource *mem, *memregion, *dmareq; | ||
252 | int ret; | ||
253 | |||
254 | spdif = kzalloc(sizeof(struct tegra_spdif), GFP_KERNEL); | ||
255 | if (!spdif) { | ||
256 | dev_err(&pdev->dev, "Can't allocate tegra_spdif\n"); | ||
257 | ret = -ENOMEM; | ||
258 | goto exit; | ||
259 | } | ||
260 | dev_set_drvdata(&pdev->dev, spdif); | ||
261 | |||
262 | spdif->clk_spdif_out = clk_get(&pdev->dev, "spdif_out"); | ||
263 | if (IS_ERR(spdif->clk_spdif_out)) { | ||
264 | pr_err("Can't retrieve spdif clock\n"); | ||
265 | ret = PTR_ERR(spdif->clk_spdif_out); | ||
266 | goto err_free; | ||
267 | } | ||
268 | |||
269 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
270 | if (!mem) { | ||
271 | dev_err(&pdev->dev, "No memory resource\n"); | ||
272 | ret = -ENODEV; | ||
273 | goto err_clk_put; | ||
274 | } | ||
275 | |||
276 | dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
277 | if (!dmareq) { | ||
278 | dev_err(&pdev->dev, "No DMA resource\n"); | ||
279 | ret = -ENODEV; | ||
280 | goto err_clk_put; | ||
281 | } | ||
282 | |||
283 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
284 | DRV_NAME); | ||
285 | if (!memregion) { | ||
286 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
287 | ret = -EBUSY; | ||
288 | goto err_clk_put; | ||
289 | } | ||
290 | |||
291 | spdif->regs = ioremap(mem->start, resource_size(mem)); | ||
292 | if (!spdif->regs) { | ||
293 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
294 | ret = -ENOMEM; | ||
295 | goto err_release; | ||
296 | } | ||
297 | |||
298 | spdif->playback_dma_data.addr = mem->start + TEGRA_SPDIF_DATA_OUT; | ||
299 | spdif->playback_dma_data.wrap = 4; | ||
300 | spdif->playback_dma_data.width = 32; | ||
301 | spdif->playback_dma_data.req_sel = dmareq->start; | ||
302 | |||
303 | ret = snd_soc_register_dai(&pdev->dev, &tegra_spdif_dai); | ||
304 | if (ret) { | ||
305 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
306 | ret = -ENOMEM; | ||
307 | goto err_unmap; | ||
308 | } | ||
309 | |||
310 | tegra_spdif_debug_add(spdif); | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | err_unmap: | ||
315 | iounmap(spdif->regs); | ||
316 | err_release: | ||
317 | release_mem_region(mem->start, resource_size(mem)); | ||
318 | err_clk_put: | ||
319 | clk_put(spdif->clk_spdif_out); | ||
320 | err_free: | ||
321 | kfree(spdif); | ||
322 | exit: | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | static int __devexit tegra_spdif_platform_remove(struct platform_device *pdev) | ||
327 | { | ||
328 | struct tegra_spdif *spdif = dev_get_drvdata(&pdev->dev); | ||
329 | struct resource *res; | ||
330 | |||
331 | snd_soc_unregister_dai(&pdev->dev); | ||
332 | |||
333 | tegra_spdif_debug_remove(spdif); | ||
334 | |||
335 | iounmap(spdif->regs); | ||
336 | |||
337 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
338 | release_mem_region(res->start, resource_size(res)); | ||
339 | |||
340 | clk_put(spdif->clk_spdif_out); | ||
341 | |||
342 | kfree(spdif); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static struct platform_driver tegra_spdif_driver = { | ||
348 | .driver = { | ||
349 | .name = DRV_NAME, | ||
350 | .owner = THIS_MODULE, | ||
351 | }, | ||
352 | .probe = tegra_spdif_platform_probe, | ||
353 | .remove = __devexit_p(tegra_spdif_platform_remove), | ||
354 | }; | ||
355 | |||
356 | static int __init snd_tegra_spdif_init(void) | ||
357 | { | ||
358 | return platform_driver_register(&tegra_spdif_driver); | ||
359 | } | ||
360 | module_init(snd_tegra_spdif_init); | ||
361 | |||
362 | static void __exit snd_tegra_spdif_exit(void) | ||
363 | { | ||
364 | platform_driver_unregister(&tegra_spdif_driver); | ||
365 | } | ||
366 | module_exit(snd_tegra_spdif_exit); | ||
367 | |||
368 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
369 | MODULE_DESCRIPTION("Tegra SPDIF ASoC driver"); | ||
370 | MODULE_LICENSE("GPL"); | ||
371 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_spdif.h b/sound/soc/tegra/tegra_spdif.h new file mode 100644 index 000000000000..2e03db430279 --- /dev/null +++ b/sound/soc/tegra/tegra_spdif.h | |||
@@ -0,0 +1,473 @@ | |||
1 | /* | ||
2 | * tegra_spdif.h - Definitions for Tegra SPDIF driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * Copyright (c) 2008-2009, NVIDIA Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
22 | * 02110-1301 USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef __TEGRA_SPDIF_H__ | ||
27 | #define __TEGRA_SPDIF_H__ | ||
28 | |||
29 | #include "tegra_pcm.h" | ||
30 | |||
31 | /* Offsets from TEGRA_SPDIF_BASE */ | ||
32 | |||
33 | #define TEGRA_SPDIF_CTRL 0x0 | ||
34 | #define TEGRA_SPDIF_STATUS 0x4 | ||
35 | #define TEGRA_SPDIF_STROBE_CTRL 0x8 | ||
36 | #define TEGRA_SPDIF_DATA_FIFO_CSR 0x0C | ||
37 | #define TEGRA_SPDIF_DATA_OUT 0x40 | ||
38 | #define TEGRA_SPDIF_DATA_IN 0x80 | ||
39 | #define TEGRA_SPDIF_CH_STA_RX_A 0x100 | ||
40 | #define TEGRA_SPDIF_CH_STA_RX_B 0x104 | ||
41 | #define TEGRA_SPDIF_CH_STA_RX_C 0x108 | ||
42 | #define TEGRA_SPDIF_CH_STA_RX_D 0x10C | ||
43 | #define TEGRA_SPDIF_CH_STA_RX_E 0x110 | ||
44 | #define TEGRA_SPDIF_CH_STA_RX_F 0x114 | ||
45 | #define TEGRA_SPDIF_CH_STA_TX_A 0x140 | ||
46 | #define TEGRA_SPDIF_CH_STA_TX_B 0x144 | ||
47 | #define TEGRA_SPDIF_CH_STA_TX_C 0x148 | ||
48 | #define TEGRA_SPDIF_CH_STA_TX_D 0x14C | ||
49 | #define TEGRA_SPDIF_CH_STA_TX_E 0x150 | ||
50 | #define TEGRA_SPDIF_CH_STA_TX_F 0x154 | ||
51 | #define TEGRA_SPDIF_USR_STA_RX_A 0x180 | ||
52 | #define TEGRA_SPDIF_USR_DAT_TX_A 0x1C0 | ||
53 | |||
54 | /* Fields in TEGRA_SPDIF_CTRL */ | ||
55 | |||
56 | /* Start capturing from 0=right, 1=left channel */ | ||
57 | #define TEGRA_SPDIF_CTRL_CAP_LC (1 << 30) | ||
58 | |||
59 | /* SPDIF receiver(RX) enable */ | ||
60 | #define TEGRA_SPDIF_CTRL_RX_EN (1 << 29) | ||
61 | |||
62 | /* SPDIF Transmitter(TX) enable */ | ||
63 | #define TEGRA_SPDIF_CTRL_TX_EN (1 << 28) | ||
64 | |||
65 | /* Transmit Channel status */ | ||
66 | #define TEGRA_SPDIF_CTRL_TC_EN (1 << 27) | ||
67 | |||
68 | /* Transmit user Data */ | ||
69 | #define TEGRA_SPDIF_CTRL_TU_EN (1 << 26) | ||
70 | |||
71 | /* Interrupt on transmit error */ | ||
72 | #define TEGRA_SPDIF_CTRL_IE_TXE (1 << 25) | ||
73 | |||
74 | /* Interrupt on receive error */ | ||
75 | #define TEGRA_SPDIF_CTRL_IE_RXE (1 << 24) | ||
76 | |||
77 | /* Interrupt on invalid preamble */ | ||
78 | #define TEGRA_SPDIF_CTRL_IE_P (1 << 23) | ||
79 | |||
80 | /* Interrupt on "B" preamble */ | ||
81 | #define TEGRA_SPDIF_CTRL_IE_B (1 << 22) | ||
82 | |||
83 | /* Interrupt when block of channel status received */ | ||
84 | #define TEGRA_SPDIF_CTRL_IE_C (1 << 21) | ||
85 | |||
86 | /* Interrupt when a valid information unit (IU) is received */ | ||
87 | #define TEGRA_SPDIF_CTRL_IE_U (1 << 20) | ||
88 | |||
89 | /* Interrupt when RX user FIFO attention level is reached */ | ||
90 | #define TEGRA_SPDIF_CTRL_QE_RU (1 << 19) | ||
91 | |||
92 | /* Interrupt when TX user FIFO attention level is reached */ | ||
93 | #define TEGRA_SPDIF_CTRL_QE_TU (1 << 18) | ||
94 | |||
95 | /* Interrupt when RX data FIFO attention level is reached */ | ||
96 | #define TEGRA_SPDIF_CTRL_QE_RX (1 << 17) | ||
97 | |||
98 | /* Interrupt when TX data FIFO attention level is reached */ | ||
99 | #define TEGRA_SPDIF_CTRL_QE_TX (1 << 16) | ||
100 | |||
101 | /* Loopback test mode enable */ | ||
102 | #define TEGRA_SPDIF_CTRL_LBK_EN (1 << 15) | ||
103 | |||
104 | /* | ||
105 | * Pack data mode: | ||
106 | * 0 = Single data (16 bit needs to be padded to match the | ||
107 | * interface data bit size). | ||
108 | * 1 = Packeted left/right channel data into a single word. | ||
109 | */ | ||
110 | #define TEGRA_SPDIF_CTRL_PACK (1 << 14) | ||
111 | |||
112 | /* | ||
113 | * 00 = 16bit data | ||
114 | * 01 = 20bit data | ||
115 | * 10 = 24bit data | ||
116 | * 11 = raw data | ||
117 | */ | ||
118 | #define TEGRA_SPDIF_BIT_MODE_16BIT 0 | ||
119 | #define TEGRA_SPDIF_BIT_MODE_20BIT 1 | ||
120 | #define TEGRA_SPDIF_BIT_MODE_24BIT 2 | ||
121 | #define TEGRA_SPDIF_BIT_MODE_RAW 3 | ||
122 | |||
123 | #define TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT 12 | ||
124 | #define TEGRA_SPDIF_CTRL_BIT_MODE_MASK (3 << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
125 | #define TEGRA_SPDIF_CTRL_BIT_MODE_16BIT (TEGRA_SPDIF_BIT_MODE_16BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
126 | #define TEGRA_SPDIF_CTRL_BIT_MODE_20BIT (TEGRA_SPDIF_BIT_MODE_20BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
127 | #define TEGRA_SPDIF_CTRL_BIT_MODE_24BIT (TEGRA_SPDIF_BIT_MODE_24BIT << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
128 | #define TEGRA_SPDIF_CTRL_BIT_MODE_RAW (TEGRA_SPDIF_BIT_MODE_RAW << TEGRA_SPDIF_CTRL_BIT_MODE_SHIFT) | ||
129 | |||
130 | /* Fields in TEGRA_SPDIF_STATUS */ | ||
131 | |||
132 | /* | ||
133 | * Note: IS_P, IS_B, IS_C, and IS_U are sticky bits. Software must | ||
134 | * write a 1 to the corresponding bit location to clear the status. | ||
135 | */ | ||
136 | |||
137 | /* | ||
138 | * Receiver(RX) shifter is busy receiving data. | ||
139 | * This bit is asserted when the receiver first locked onto the | ||
140 | * preamble of the data stream after RX_EN is asserted. This bit is | ||
141 | * deasserted when either, | ||
142 | * (a) the end of a frame is reached after RX_EN is deeasserted, or | ||
143 | * (b) the SPDIF data stream becomes inactive. | ||
144 | */ | ||
145 | #define TEGRA_SPDIF_STATUS_RX_BSY (1 << 29) | ||
146 | |||
147 | /* | ||
148 | * Transmitter(TX) shifter is busy transmitting data. | ||
149 | * This bit is asserted when TX_EN is asserted. | ||
150 | * This bit is deasserted when the end of a frame is reached after | ||
151 | * TX_EN is deasserted. | ||
152 | */ | ||
153 | #define TEGRA_SPDIF_STATUS_TX_BSY (1 << 28) | ||
154 | |||
155 | /* | ||
156 | * TX is busy shifting out channel status. | ||
157 | * This bit is asserted when both TX_EN and TC_EN are asserted and | ||
158 | * data from CH_STA_TX_A register is loaded into the internal shifter. | ||
159 | * This bit is deasserted when either, | ||
160 | * (a) the end of a frame is reached after TX_EN is deasserted, or | ||
161 | * (b) CH_STA_TX_F register is loaded into the internal shifter. | ||
162 | */ | ||
163 | #define TEGRA_SPDIF_STATUS_TC_BSY (1 << 27) | ||
164 | |||
165 | /* | ||
166 | * TX User data FIFO busy. | ||
167 | * This bit is asserted when TX_EN and TXU_EN are asserted and | ||
168 | * there's data in the TX user FIFO. This bit is deassert when either, | ||
169 | * (a) the end of a frame is reached after TX_EN is deasserted, or | ||
170 | * (b) there's no data left in the TX user FIFO. | ||
171 | */ | ||
172 | #define TEGRA_SPDIF_STATUS_TU_BSY (1 << 26) | ||
173 | |||
174 | /* TX FIFO Underrun error status */ | ||
175 | #define TEGRA_SPDIF_STATUS_TX_ERR (1 << 25) | ||
176 | |||
177 | /* RX FIFO Overrun error status */ | ||
178 | #define TEGRA_SPDIF_STATUS_RX_ERR (1 << 24) | ||
179 | |||
180 | /* Preamble status: 0=Preamble OK, 1=bad/missing preamble */ | ||
181 | #define TEGRA_SPDIF_STATUS_IS_P (1 << 23) | ||
182 | |||
183 | /* B-preamble detection status: 0=not detected, 1=B-preamble detected */ | ||
184 | #define TEGRA_SPDIF_STATUS_IS_B (1 << 22) | ||
185 | |||
186 | /* | ||
187 | * RX channel block data receive status: | ||
188 | * 0=entire block not recieved yet. | ||
189 | * 1=received entire block of channel status, | ||
190 | */ | ||
191 | #define TEGRA_SPDIF_STATUS_IS_C (1 << 21) | ||
192 | |||
193 | /* RX User Data Valid flag: 1=valid IU detected, 0 = no IU detected. */ | ||
194 | #define TEGRA_SPDIF_STATUS_IS_U (1 << 20) | ||
195 | |||
196 | /* | ||
197 | * RX User FIFO Status: | ||
198 | * 1=attention level reached, 0=attention level not reached. | ||
199 | */ | ||
200 | #define TEGRA_SPDIF_STATUS_QS_RU (1 << 19) | ||
201 | |||
202 | /* | ||
203 | * TX User FIFO Status: | ||
204 | * 1=attention level reached, 0=attention level not reached. | ||
205 | */ | ||
206 | #define TEGRA_SPDIF_STATUS_QS_TU (1 << 18) | ||
207 | |||
208 | /* | ||
209 | * RX Data FIFO Status: | ||
210 | * 1=attention level reached, 0=attention level not reached. | ||
211 | */ | ||
212 | #define TEGRA_SPDIF_STATUS_QS_RX (1 << 17) | ||
213 | |||
214 | /* | ||
215 | * TX Data FIFO Status: | ||
216 | * 1=attention level reached, 0=attention level not reached. | ||
217 | */ | ||
218 | #define TEGRA_SPDIF_STATUS_QS_TX (1 << 16) | ||
219 | |||
220 | /* Fields in TEGRA_SPDIF_STROBE_CTRL */ | ||
221 | |||
222 | /* | ||
223 | * Indicates the approximate number of detected SPDIFIN clocks within a | ||
224 | * bi-phase period. | ||
225 | */ | ||
226 | #define TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT 16 | ||
227 | #define TEGRA_SPDIF_STROBE_CTRL_PERIOD_MASK (0xff << TEGRA_SPDIF_STROBE_CTRL_PERIOD_SHIFT) | ||
228 | |||
229 | /* Data strobe mode: 0=Auto-locked 1=Manual locked */ | ||
230 | #define TEGRA_SPDIF_STROBE_CTRL_STROBE (1 << 15) | ||
231 | |||
232 | /* | ||
233 | * Manual data strobe time within the bi-phase clock period (in terms of | ||
234 | * the number of over-sampling clocks). | ||
235 | */ | ||
236 | #define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT 8 | ||
237 | #define TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_MASK (0x1f << TEGRA_SPDIF_STROBE_CTRL_DATA_STROBES_SHIFT) | ||
238 | |||
239 | /* | ||
240 | * Manual SPDIFIN bi-phase clock period (in terms of the number of | ||
241 | * over-sampling clocks). | ||
242 | */ | ||
243 | #define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT 0 | ||
244 | #define TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_MASK (0x3f << TEGRA_SPDIF_STROBE_CTRL_CLOCK_PERIOD_SHIFT) | ||
245 | |||
246 | /* Fields in SPDIF_DATA_FIFO_CSR */ | ||
247 | |||
248 | /* Clear Receiver User FIFO (RX USR.FIFO) */ | ||
249 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_CLR (1 << 31) | ||
250 | |||
251 | #define TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT 0 | ||
252 | #define TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS 1 | ||
253 | #define TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS 2 | ||
254 | #define TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS 3 | ||
255 | |||
256 | /* RU FIFO attention level */ | ||
257 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT 29 | ||
258 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_MASK \ | ||
259 | (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
260 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU1_WORD_FULL \ | ||
261 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
262 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU2_WORD_FULL \ | ||
263 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
264 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU3_WORD_FULL \ | ||
265 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
266 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_RU4_WORD_FULL \ | ||
267 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RU_ATN_LVL_SHIFT) | ||
268 | |||
269 | /* Number of RX USR.FIFO levels with valid data. */ | ||
270 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT 24 | ||
271 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_MASK (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RU_FULL_COUNT_SHIFT) | ||
272 | |||
273 | /* Clear Transmitter User FIFO (TX USR.FIFO) */ | ||
274 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_CLR (1 << 23) | ||
275 | |||
276 | /* TU FIFO attention level */ | ||
277 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT 21 | ||
278 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_MASK \ | ||
279 | (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
280 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU1_WORD_FULL \ | ||
281 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
282 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU2_WORD_FULL \ | ||
283 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_TWO_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
284 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU3_WORD_FULL \ | ||
285 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_THREE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
286 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_TU4_WORD_FULL \ | ||
287 | (TEGRA_SPDIF_FIFO_ATN_LVL_U_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TU_ATN_LVL_SHIFT) | ||
288 | |||
289 | /* Number of TX USR.FIFO levels that could be filled. */ | ||
290 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT 16 | ||
291 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TU_EMPTY_COUNT_SHIFT) | ||
292 | |||
293 | /* Clear Receiver Data FIFO (RX DATA.FIFO) */ | ||
294 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_CLR (1 << 15) | ||
295 | |||
296 | #define TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT 0 | ||
297 | #define TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS 1 | ||
298 | #define TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS 2 | ||
299 | #define TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS 3 | ||
300 | |||
301 | /* RU FIFO attention level */ | ||
302 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT 13 | ||
303 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_MASK \ | ||
304 | (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
305 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU1_WORD_FULL \ | ||
306 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
307 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU4_WORD_FULL \ | ||
308 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
309 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU8_WORD_FULL \ | ||
310 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
311 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_RU12_WORD_FULL \ | ||
312 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_RX_ATN_LVL_SHIFT) | ||
313 | |||
314 | /* Number of RX DATA.FIFO levels with valid data. */ | ||
315 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT 8 | ||
316 | #define TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_MASK (0x1f << TEGRA_SPDIF_DATA_FIFO_CSR_RX_FULL_COUNT_SHIFT) | ||
317 | |||
318 | /* Clear Transmitter Data FIFO (TX DATA.FIFO) */ | ||
319 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_CLR (1 << 7) | ||
320 | |||
321 | /* TU FIFO attention level */ | ||
322 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT 5 | ||
323 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_MASK \ | ||
324 | (0x3 << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
325 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU1_WORD_FULL \ | ||
326 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_ONE_SLOT << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
327 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU4_WORD_FULL \ | ||
328 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_FOUR_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
329 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU8_WORD_FULL \ | ||
330 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_EIGHT_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
331 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_TU12_WORD_FULL \ | ||
332 | (TEGRA_SPDIF_FIFO_ATN_LVL_D_TWELVE_SLOTS << TEGRA_SPDIF_DATA_FIFO_CSR_TX_ATN_LVL_SHIFT) | ||
333 | |||
334 | /* Number of TX DATA.FIFO levels that could be filled. */ | ||
335 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT 0 | ||
336 | #define TEGRA_SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_MASK (0x1f << SPDIF_DATA_FIFO_CSR_TX_EMPTY_COUNT_SHIFT) | ||
337 | |||
338 | /* Fields in TEGRA_SPDIF_DATA_OUT */ | ||
339 | |||
340 | /* | ||
341 | * This register has 5 different formats: | ||
342 | * 16-bit (BIT_MODE=00, PACK=0) | ||
343 | * 20-bit (BIT_MODE=01, PACK=0) | ||
344 | * 24-bit (BIT_MODE=10, PACK=0) | ||
345 | * raw (BIT_MODE=11, PACK=0) | ||
346 | * 16-bit packed (BIT_MODE=00, PACK=1) | ||
347 | */ | ||
348 | |||
349 | #define TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT 0 | ||
350 | #define TEGRA_SPDIF_DATA_OUT_DATA_16_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_SHIFT) | ||
351 | |||
352 | #define TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT 0 | ||
353 | #define TEGRA_SPDIF_DATA_OUT_DATA_20_MASK (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_20_SHIFT) | ||
354 | |||
355 | #define TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT 0 | ||
356 | #define TEGRA_SPDIF_DATA_OUT_DATA_24_MASK (0xffffff << TEGRA_SPDIF_DATA_OUT_DATA_24_SHIFT) | ||
357 | |||
358 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_P (1 << 31) | ||
359 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_C (1 << 30) | ||
360 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_U (1 << 29) | ||
361 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_V (1 << 28) | ||
362 | |||
363 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT 8 | ||
364 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_MASK (0xfffff << TEGRA_SPDIF_DATA_OUT_DATA_RAW_DATA_SHIFT) | ||
365 | |||
366 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT 4 | ||
367 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_MASK (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_AUX_SHIFT) | ||
368 | |||
369 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT 0 | ||
370 | #define TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_OUT_DATA_RAW_PREAMBLE_SHIFT) | ||
371 | |||
372 | #define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT 16 | ||
373 | #define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_RIGHT_SHIFT) | ||
374 | |||
375 | #define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT 0 | ||
376 | #define TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA_SPDIF_DATA_OUT_DATA_16_PACKED_LEFT_SHIFT) | ||
377 | |||
378 | /* Fields in TEGRA_SPDIF_DATA_IN */ | ||
379 | |||
380 | /* | ||
381 | * This register has 5 different formats: | ||
382 | * 16-bit (BIT_MODE=00, PACK=0) | ||
383 | * 20-bit (BIT_MODE=01, PACK=0) | ||
384 | * 24-bit (BIT_MODE=10, PACK=0) | ||
385 | * raw (BIT_MODE=11, PACK=0) | ||
386 | * 16-bit packed (BIT_MODE=00, PACK=1) | ||
387 | * | ||
388 | * Bits 31:24 are common to all modes except 16-bit packed | ||
389 | */ | ||
390 | |||
391 | #define TEGRA_SPDIF_DATA_IN_DATA_P (1 << 31) | ||
392 | #define TEGRA_SPDIF_DATA_IN_DATA_C (1 << 30) | ||
393 | #define TEGRA_SPDIF_DATA_IN_DATA_U (1 << 29) | ||
394 | #define TEGRA_SPDIF_DATA_IN_DATA_V (1 << 28) | ||
395 | |||
396 | #define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT 24 | ||
397 | #define TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_PREAMBLE_SHIFT) | ||
398 | |||
399 | #define TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT 0 | ||
400 | #define TEGRA_SPDIF_DATA_IN_DATA_16_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_SHIFT) | ||
401 | |||
402 | #define TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT 0 | ||
403 | #define TEGRA_SPDIF_DATA_IN_DATA_20_MASK (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_20_SHIFT) | ||
404 | |||
405 | #define TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT 0 | ||
406 | #define TEGRA_SPDIF_DATA_IN_DATA_24_MASK (0xffffff << TEGRA_SPDIF_DATA_IN_DATA_24_SHIFT) | ||
407 | |||
408 | #define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT 8 | ||
409 | #define TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_MASK (0xfffff << TEGRA_SPDIF_DATA_IN_DATA_RAW_DATA_SHIFT) | ||
410 | |||
411 | #define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT 4 | ||
412 | #define TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_AUX_SHIFT) | ||
413 | |||
414 | #define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT 0 | ||
415 | #define TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_MASK (0xf << TEGRA_SPDIF_DATA_IN_DATA_RAW_PREAMBLE_SHIFT) | ||
416 | |||
417 | #define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT 16 | ||
418 | #define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_RIGHT_SHIFT) | ||
419 | |||
420 | #define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT 0 | ||
421 | #define TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_MASK (0xffff << TEGRA_SPDIF_DATA_IN_DATA_16_PACKED_LEFT_SHIFT) | ||
422 | |||
423 | /* Fields in TEGRA_SPDIF_CH_STA_RX_A */ | ||
424 | /* Fields in TEGRA_SPDIF_CH_STA_RX_B */ | ||
425 | /* Fields in TEGRA_SPDIF_CH_STA_RX_C */ | ||
426 | /* Fields in TEGRA_SPDIF_CH_STA_RX_D */ | ||
427 | /* Fields in TEGRA_SPDIF_CH_STA_RX_E */ | ||
428 | /* Fields in TEGRA_SPDIF_CH_STA_RX_F */ | ||
429 | |||
430 | /* | ||
431 | * The 6-word receive channel data page buffer holds a block (192 frames) of | ||
432 | * channel status information. The order of receive is from LSB to MSB | ||
433 | * bit, and from CH_STA_RX_A to CH_STA_RX_F then back to CH_STA_RX_A. | ||
434 | */ | ||
435 | |||
436 | /* Fields in TEGRA_SPDIF_CH_STA_TX_A */ | ||
437 | /* Fields in TEGRA_SPDIF_CH_STA_TX_B */ | ||
438 | /* Fields in TEGRA_SPDIF_CH_STA_TX_C */ | ||
439 | /* Fields in TEGRA_SPDIF_CH_STA_TX_D */ | ||
440 | /* Fields in TEGRA_SPDIF_CH_STA_TX_E */ | ||
441 | /* Fields in TEGRA_SPDIF_CH_STA_TX_F */ | ||
442 | |||
443 | /* | ||
444 | * The 6-word transmit channel data page buffer holds a block (192 frames) of | ||
445 | * channel status information. The order of transmission is from LSB to MSB | ||
446 | * bit, and from CH_STA_TX_A to CH_STA_TX_F then back to CH_STA_TX_A. | ||
447 | */ | ||
448 | |||
449 | /* Fields in TEGRA_SPDIF_USR_STA_RX_A */ | ||
450 | |||
451 | /* | ||
452 | * This 4-word deep FIFO receives user FIFO field information. The order of | ||
453 | * receive is from LSB to MSB bit. | ||
454 | */ | ||
455 | |||
456 | /* Fields in TEGRA_SPDIF_USR_DAT_TX_A */ | ||
457 | |||
458 | /* | ||
459 | * This 4-word deep FIFO transmits user FIFO field information. The order of | ||
460 | * transmission is from LSB to MSB bit. | ||
461 | */ | ||
462 | |||
463 | struct tegra_spdif { | ||
464 | struct clk *clk_spdif_out; | ||
465 | int clk_refs; | ||
466 | struct tegra_pcm_dma_params capture_dma_data; | ||
467 | struct tegra_pcm_dma_params playback_dma_data; | ||
468 | void __iomem *regs; | ||
469 | struct dentry *debug; | ||
470 | u32 reg_ctrl; | ||
471 | }; | ||
472 | |||
473 | #endif | ||
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 0d6738a8b29a..a42e9ac30f28 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c | |||
@@ -267,7 +267,7 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
267 | } | 267 | } |
268 | machine->gpio_requested |= GPIO_HP_MUTE; | 268 | machine->gpio_requested |= GPIO_HP_MUTE; |
269 | 269 | ||
270 | gpio_direction_output(pdata->gpio_hp_mute, 0); | 270 | gpio_direction_output(pdata->gpio_hp_mute, 1); |
271 | } | 271 | } |
272 | 272 | ||
273 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | 273 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { |
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index f4aa4e03c888..34aa972669ed 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c | |||
@@ -288,9 +288,10 @@ static void txx9aclc_pcm_free_dma_buffers(struct snd_pcm *pcm) | |||
288 | snd_pcm_lib_preallocate_free_for_all(pcm); | 288 | snd_pcm_lib_preallocate_free_for_all(pcm); |
289 | } | 289 | } |
290 | 290 | ||
291 | static int txx9aclc_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | 291 | static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) |
292 | struct snd_pcm *pcm) | ||
293 | { | 292 | { |
293 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
294 | struct snd_pcm *pcm = rtd->pcm; | ||
294 | struct platform_device *pdev = to_platform_device(dai->platform->dev); | 295 | struct platform_device *pdev = to_platform_device(dai->platform->dev); |
295 | struct txx9aclc_soc_device *dev; | 296 | struct txx9aclc_soc_device *dev; |
296 | struct resource *r; | 297 | struct resource *r; |