diff options
Diffstat (limited to 'drivers/gpu/drm/msm/hdmi/hdmi.c')
-rw-r--r-- | drivers/gpu/drm/msm/hdmi/hdmi.c | 117 |
1 files changed, 116 insertions, 1 deletions
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 51b9ea552f97..973720792236 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
20 | #include <linux/of_gpio.h> | 20 | #include <linux/of_gpio.h> |
21 | 21 | ||
22 | #include <sound/hdmi-codec.h> | ||
22 | #include "hdmi.h" | 23 | #include "hdmi.h" |
23 | 24 | ||
24 | void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) | 25 | void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on) |
@@ -434,6 +435,111 @@ static int msm_hdmi_get_gpio(struct device_node *of_node, const char *name) | |||
434 | return gpio; | 435 | return gpio; |
435 | } | 436 | } |
436 | 437 | ||
438 | /* | ||
439 | * HDMI audio codec callbacks | ||
440 | */ | ||
441 | static int msm_hdmi_audio_hw_params(struct device *dev, void *data, | ||
442 | struct hdmi_codec_daifmt *daifmt, | ||
443 | struct hdmi_codec_params *params) | ||
444 | { | ||
445 | struct hdmi *hdmi = dev_get_drvdata(dev); | ||
446 | unsigned int chan; | ||
447 | unsigned int channel_allocation = 0; | ||
448 | unsigned int rate; | ||
449 | unsigned int level_shift = 0; /* 0dB */ | ||
450 | bool down_mix = false; | ||
451 | |||
452 | dev_dbg(dev, "%u Hz, %d bit, %d channels\n", params->sample_rate, | ||
453 | params->sample_width, params->cea.channels); | ||
454 | |||
455 | switch (params->cea.channels) { | ||
456 | case 2: | ||
457 | /* FR and FL speakers */ | ||
458 | channel_allocation = 0; | ||
459 | chan = MSM_HDMI_AUDIO_CHANNEL_2; | ||
460 | break; | ||
461 | case 4: | ||
462 | /* FC, LFE, FR and FL speakers */ | ||
463 | channel_allocation = 0x3; | ||
464 | chan = MSM_HDMI_AUDIO_CHANNEL_4; | ||
465 | break; | ||
466 | case 6: | ||
467 | /* RR, RL, FC, LFE, FR and FL speakers */ | ||
468 | channel_allocation = 0x0B; | ||
469 | chan = MSM_HDMI_AUDIO_CHANNEL_6; | ||
470 | break; | ||
471 | case 8: | ||
472 | /* FRC, FLC, RR, RL, FC, LFE, FR and FL speakers */ | ||
473 | channel_allocation = 0x1F; | ||
474 | chan = MSM_HDMI_AUDIO_CHANNEL_8; | ||
475 | break; | ||
476 | default: | ||
477 | return -EINVAL; | ||
478 | } | ||
479 | |||
480 | switch (params->sample_rate) { | ||
481 | case 32000: | ||
482 | rate = HDMI_SAMPLE_RATE_32KHZ; | ||
483 | break; | ||
484 | case 44100: | ||
485 | rate = HDMI_SAMPLE_RATE_44_1KHZ; | ||
486 | break; | ||
487 | case 48000: | ||
488 | rate = HDMI_SAMPLE_RATE_48KHZ; | ||
489 | break; | ||
490 | case 88200: | ||
491 | rate = HDMI_SAMPLE_RATE_88_2KHZ; | ||
492 | break; | ||
493 | case 96000: | ||
494 | rate = HDMI_SAMPLE_RATE_96KHZ; | ||
495 | break; | ||
496 | case 176400: | ||
497 | rate = HDMI_SAMPLE_RATE_176_4KHZ; | ||
498 | break; | ||
499 | case 192000: | ||
500 | rate = HDMI_SAMPLE_RATE_192KHZ; | ||
501 | break; | ||
502 | default: | ||
503 | dev_err(dev, "rate[%d] not supported!\n", | ||
504 | params->sample_rate); | ||
505 | return -EINVAL; | ||
506 | } | ||
507 | |||
508 | msm_hdmi_audio_set_sample_rate(hdmi, rate); | ||
509 | msm_hdmi_audio_info_setup(hdmi, 1, chan, channel_allocation, | ||
510 | level_shift, down_mix); | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | static void msm_hdmi_audio_shutdown(struct device *dev, void *data) | ||
516 | { | ||
517 | struct hdmi *hdmi = dev_get_drvdata(dev); | ||
518 | |||
519 | msm_hdmi_audio_info_setup(hdmi, 0, 0, 0, 0, 0); | ||
520 | } | ||
521 | |||
522 | static const struct hdmi_codec_ops msm_hdmi_audio_codec_ops = { | ||
523 | .hw_params = msm_hdmi_audio_hw_params, | ||
524 | .audio_shutdown = msm_hdmi_audio_shutdown, | ||
525 | }; | ||
526 | |||
527 | static struct hdmi_codec_pdata codec_data = { | ||
528 | .ops = &msm_hdmi_audio_codec_ops, | ||
529 | .max_i2s_channels = 8, | ||
530 | .i2s = 1, | ||
531 | }; | ||
532 | |||
533 | static int msm_hdmi_register_audio_driver(struct hdmi *hdmi, struct device *dev) | ||
534 | { | ||
535 | hdmi->audio_pdev = platform_device_register_data(dev, | ||
536 | HDMI_CODEC_DRV_NAME, | ||
537 | PLATFORM_DEVID_AUTO, | ||
538 | &codec_data, | ||
539 | sizeof(codec_data)); | ||
540 | return PTR_ERR_OR_ZERO(hdmi->audio_pdev); | ||
541 | } | ||
542 | |||
437 | static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) | 543 | static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) |
438 | { | 544 | { |
439 | struct drm_device *drm = dev_get_drvdata(master); | 545 | struct drm_device *drm = dev_get_drvdata(master); |
@@ -441,7 +547,7 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
441 | static struct hdmi_platform_config *hdmi_cfg; | 547 | static struct hdmi_platform_config *hdmi_cfg; |
442 | struct hdmi *hdmi; | 548 | struct hdmi *hdmi; |
443 | struct device_node *of_node = dev->of_node; | 549 | struct device_node *of_node = dev->of_node; |
444 | int i; | 550 | int i, err; |
445 | 551 | ||
446 | hdmi_cfg = (struct hdmi_platform_config *) | 552 | hdmi_cfg = (struct hdmi_platform_config *) |
447 | of_device_get_match_data(dev); | 553 | of_device_get_match_data(dev); |
@@ -468,6 +574,12 @@ static int msm_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
468 | return PTR_ERR(hdmi); | 574 | return PTR_ERR(hdmi); |
469 | priv->hdmi = hdmi; | 575 | priv->hdmi = hdmi; |
470 | 576 | ||
577 | err = msm_hdmi_register_audio_driver(hdmi, dev); | ||
578 | if (err) { | ||
579 | DRM_ERROR("Failed to attach an audio codec %d\n", err); | ||
580 | hdmi->audio_pdev = NULL; | ||
581 | } | ||
582 | |||
471 | return 0; | 583 | return 0; |
472 | } | 584 | } |
473 | 585 | ||
@@ -477,6 +589,9 @@ static void msm_hdmi_unbind(struct device *dev, struct device *master, | |||
477 | struct drm_device *drm = dev_get_drvdata(master); | 589 | struct drm_device *drm = dev_get_drvdata(master); |
478 | struct msm_drm_private *priv = drm->dev_private; | 590 | struct msm_drm_private *priv = drm->dev_private; |
479 | if (priv->hdmi) { | 591 | if (priv->hdmi) { |
592 | if (priv->hdmi->audio_pdev) | ||
593 | platform_device_unregister(priv->hdmi->audio_pdev); | ||
594 | |||
480 | msm_hdmi_destroy(priv->hdmi); | 595 | msm_hdmi_destroy(priv->hdmi); |
481 | priv->hdmi = NULL; | 596 | priv->hdmi = NULL; |
482 | } | 597 | } |