Merge tag 'ux500-core-for-v3.17-1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / sound / pci / hda / hda_i915.c
1 /*
2  *  hda_i915.c - routines for Haswell HDA controller power well support
3  *
4  *  This program is free software; you can redistribute it and/or modify it
5  *  under the terms of the GNU General Public License as published by the Free
6  *  Software Foundation; either version 2 of the License, or (at your option)
7  *  any later version.
8  *
9  *  This program is distributed in the hope that it will be useful, but
10  *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  *  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  *  for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software Foundation,
16  *  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  */
18
19 #include <linux/init.h>
20 #include <linux/module.h>
21 #include <sound/core.h>
22 #include <drm/i915_powerwell.h>
23 #include "hda_priv.h"
24 #include "hda_i915.h"
25
26 /* Intel HSW/BDW display HDA controller Extended Mode registers.
27  * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display
28  * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N
29  * The values will be lost when the display power well is disabled.
30  */
31 #define ICH6_REG_EM4                    0x100c
32 #define ICH6_REG_EM5                    0x1010
33
34 static int (*get_power)(void);
35 static int (*put_power)(void);
36 static int (*get_cdclk)(void);
37
38 int hda_display_power(bool enable)
39 {
40         if (!get_power || !put_power)
41                 return -ENODEV;
42
43         pr_debug("HDA display power %s \n",
44                         enable ? "Enable" : "Disable");
45         if (enable)
46                 return get_power();
47         else
48                 return put_power();
49 }
50
51 void haswell_set_bclk(struct azx *chip)
52 {
53         int cdclk_freq;
54         unsigned int bclk_m, bclk_n;
55
56         if (!get_cdclk)
57                 return;
58
59         cdclk_freq = get_cdclk();
60         switch (cdclk_freq) {
61         case 337500:
62                 bclk_m = 16;
63                 bclk_n = 225;
64                 break;
65
66         case 450000:
67         default: /* default CDCLK 450MHz */
68                 bclk_m = 4;
69                 bclk_n = 75;
70                 break;
71
72         case 540000:
73                 bclk_m = 4;
74                 bclk_n = 90;
75                 break;
76
77         case 675000:
78                 bclk_m = 8;
79                 bclk_n = 225;
80                 break;
81         }
82
83         azx_writew(chip, EM4, bclk_m);
84         azx_writew(chip, EM5, bclk_n);
85 }
86
87
88 int hda_i915_init(void)
89 {
90         int err = 0;
91
92         get_power = symbol_request(i915_request_power_well);
93         if (!get_power) {
94                 pr_warn("hda-i915: get_power symbol get fail\n");
95                 return -ENODEV;
96         }
97
98         put_power = symbol_request(i915_release_power_well);
99         if (!put_power) {
100                 symbol_put(i915_request_power_well);
101                 get_power = NULL;
102                 return -ENODEV;
103         }
104
105         get_cdclk = symbol_request(i915_get_cdclk_freq);
106         if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
107                 pr_warn("hda-i915: get_cdclk symbol get fail\n");
108
109         pr_debug("HDA driver get symbol successfully from i915 module\n");
110
111         return err;
112 }
113
114 int hda_i915_exit(void)
115 {
116         if (get_power) {
117                 symbol_put(i915_request_power_well);
118                 get_power = NULL;
119         }
120         if (put_power) {
121                 symbol_put(i915_release_power_well);
122                 put_power = NULL;
123         }
124         if (get_cdclk) {
125                 symbol_put(i915_get_cdclk_freq);
126                 get_cdclk = NULL;
127         }
128
129         return 0;
130 }