diff options
Diffstat (limited to 'sound/pci/hda/hda_i915.c')
| -rw-r--r-- | sound/pci/hda/hda_i915.c | 73 |
1 files changed, 64 insertions, 9 deletions
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c index 76c13d5b3ca..8b4940ba33d 100644 --- a/sound/pci/hda/hda_i915.c +++ b/sound/pci/hda/hda_i915.c @@ -20,31 +20,78 @@ #include <linux/module.h> #include <sound/core.h> #include <drm/i915_powerwell.h> +#include "hda_priv.h" #include "hda_i915.h" -static void (*get_power)(void); -static void (*put_power)(void); +/* Intel HSW/BDW display HDA controller Extended Mode registers. + * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display + * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N + * The values will be lost when the display power well is disabled. + */ +#define ICH6_REG_EM4 0x100c +#define ICH6_REG_EM5 0x1010 + +static int (*get_power)(void); +static int (*put_power)(void); +static int (*get_cdclk)(void); -void hda_display_power(bool enable) +int hda_display_power(bool enable) { if (!get_power || !put_power) - return; + return -ENODEV; - snd_printdd("HDA display power %s \n", + pr_debug("HDA display power %s \n", enable ? "Enable" : "Disable"); if (enable) - get_power(); + return get_power(); else - put_power(); + return put_power(); +} + +void haswell_set_bclk(struct azx *chip) +{ + int cdclk_freq; + unsigned int bclk_m, bclk_n; + + if (!get_cdclk) + return; + + cdclk_freq = get_cdclk(); + switch (cdclk_freq) { + case 337500: + bclk_m = 16; + bclk_n = 225; + break; + + case 450000: + default: /* default CDCLK 450MHz */ + bclk_m = 4; + bclk_n = 75; + break; + + case 540000: + bclk_m = 4; + bclk_n = 90; + break; + + case 675000: + bclk_m = 8; + bclk_n = 225; + break; + } + + azx_writew(chip, EM4, bclk_m); + azx_writew(chip, EM5, bclk_n); } + int hda_i915_init(void) { int err = 0; get_power = symbol_request(i915_request_power_well); if (!get_power) { - snd_printk(KERN_WARNING "hda-i915: get_power symbol get fail\n"); + pr_warn("hda-i915: get_power symbol get fail\n"); return -ENODEV; } @@ -55,7 +102,11 @@ int hda_i915_init(void) return -ENODEV; } - snd_printd("HDA driver get symbol successfully from i915 module\n"); + get_cdclk = symbol_request(i915_get_cdclk_freq); + if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ + pr_warn("hda-i915: get_cdclk symbol get fail\n"); + + pr_debug("HDA driver get symbol successfully from i915 module\n"); return err; } @@ -70,6 +121,10 @@ int hda_i915_exit(void) symbol_put(i915_release_power_well); put_power = NULL; } + if (get_cdclk) { + symbol_put(i915_get_cdclk_freq); + get_cdclk = NULL; + } return 0; } |
