aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorImre Deak <imre.deak@intel.com>2015-01-08 10:54:17 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-01-11 20:48:23 -0500
commitd7055bd653e00ef40a07065d1c94380240314c48 (patch)
tree97b7bd0cf5d4f3fb3baf5cce67148621e66f8e77
parent926981ae3325257d0bffcf7ff7ba359edb4fd7e8 (diff)
ALSA: hda: add component support
Register a component master to be used to interface with the i915 driver. This is meant to replace the current interface which is based on module symbol lookups. Note that currently we keep the existing behavior and pin the i915 module while the hda driver is loaded. Using the component interface allows us to remove this dependency once support for dynamically enabling / disabling the HDMI functionality is added to the driver. v2: - change roles between the hda and i915 components (Daniel) v3: - rename display_component to audio_component (Daniel) v4: - move removal of i915_powerwell.h from this patch to the next (Takashi) - request_module fails if module support isn't enabled, so ignore any error it returns and depend on the following NULL check of the component ops (Takashi) - change over to using dev_* instead of pr_* (Takashi) Signed-off-by: Imre Deak <imre.deak@intel.com> Reviewed-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r--sound/pci/hda/hda_i915.c142
-rw-r--r--sound/pci/hda/hda_intel.c5
-rw-r--r--sound/pci/hda/hda_intel.h4
3 files changed, 106 insertions, 45 deletions
diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c
index 66acd09f5da1..714894527e06 100644
--- a/sound/pci/hda/hda_i915.c
+++ b/sound/pci/hda/hda_i915.c
@@ -18,8 +18,10 @@
18 18
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/pci.h>
22#include <linux/component.h>
23#include <drm/i915_component.h>
21#include <sound/core.h> 24#include <sound/core.h>
22#include <drm/i915_powerwell.h>
23#include "hda_priv.h" 25#include "hda_priv.h"
24#include "hda_intel.h" 26#include "hda_intel.h"
25 27
@@ -31,32 +33,33 @@
31#define AZX_REG_EM4 0x100c 33#define AZX_REG_EM4 0x100c
32#define AZX_REG_EM5 0x1010 34#define AZX_REG_EM5 0x1010
33 35
34static int (*get_power)(void);
35static int (*put_power)(void);
36static int (*get_cdclk)(void);
37
38int hda_display_power(struct hda_intel *hda, bool enable) 36int hda_display_power(struct hda_intel *hda, bool enable)
39{ 37{
40 if (!get_power || !put_power) 38 struct i915_audio_component *acomp = &hda->audio_component;
39
40 if (!acomp->ops)
41 return -ENODEV; 41 return -ENODEV;
42 42
43 pr_debug("HDA display power %s \n", 43 dev_dbg(&hda->chip.pci->dev, "display power %s\n",
44 enable ? "Enable" : "Disable"); 44 enable ? "enable" : "disable");
45 if (enable) 45 if (enable)
46 return get_power(); 46 acomp->ops->get_power(acomp->dev);
47 else 47 else
48 return put_power(); 48 acomp->ops->put_power(acomp->dev);
49
50 return 0;
49} 51}
50 52
51void haswell_set_bclk(struct hda_intel *hda) 53void haswell_set_bclk(struct hda_intel *hda)
52{ 54{
53 int cdclk_freq; 55 int cdclk_freq;
54 unsigned int bclk_m, bclk_n; 56 unsigned int bclk_m, bclk_n;
57 struct i915_audio_component *acomp = &hda->audio_component;
55 58
56 if (!get_cdclk) 59 if (!acomp->ops)
57 return; 60 return;
58 61
59 cdclk_freq = get_cdclk(); 62 cdclk_freq = acomp->ops->get_cdclk_freq(acomp->dev);
60 switch (cdclk_freq) { 63 switch (cdclk_freq) {
61 case 337500: 64 case 337500:
62 bclk_m = 16; 65 bclk_m = 16;
@@ -84,47 +87,104 @@ void haswell_set_bclk(struct hda_intel *hda)
84 azx_writew(&hda->chip, EM5, bclk_n); 87 azx_writew(&hda->chip, EM5, bclk_n);
85} 88}
86 89
87 90static int hda_component_master_bind(struct device *dev)
88int hda_i915_init(struct hda_intel *hda)
89{ 91{
90 int err = 0; 92 struct snd_card *card = dev_get_drvdata(dev);
93 struct azx *chip = card->private_data;
94 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
95 struct i915_audio_component *acomp = &hda->audio_component;
96 int ret;
97
98 ret = component_bind_all(dev, acomp);
99 if (ret < 0)
100 return ret;
101
102 if (WARN_ON(!(acomp->dev && acomp->ops && acomp->ops->get_power &&
103 acomp->ops->put_power && acomp->ops->get_cdclk_freq))) {
104 ret = -EINVAL;
105 goto out_unbind;
106 }
91 107
92 get_power = symbol_request(i915_request_power_well); 108 /*
93 if (!get_power) { 109 * Atm, we don't support dynamic unbinding initiated by the child
94 pr_warn("hda-i915: get_power symbol get fail\n"); 110 * component, so pin its containing module until we unbind.
95 return -ENODEV; 111 */
112 if (!try_module_get(acomp->ops->owner)) {
113 ret = -ENODEV;
114 goto out_unbind;
96 } 115 }
97 116
98 put_power = symbol_request(i915_release_power_well); 117 return 0;
99 if (!put_power) { 118
100 symbol_put(i915_request_power_well); 119out_unbind:
101 get_power = NULL; 120 component_unbind_all(dev, acomp);
102 return -ENODEV; 121
122 return ret;
123}
124
125static void hda_component_master_unbind(struct device *dev)
126{
127 struct snd_card *card = dev_get_drvdata(dev);
128 struct azx *chip = card->private_data;
129 struct hda_intel *hda = container_of(chip, struct hda_intel, chip);
130 struct i915_audio_component *acomp = &hda->audio_component;
131
132 module_put(acomp->ops->owner);
133 component_unbind_all(dev, acomp);
134 WARN_ON(acomp->ops || acomp->dev);
135}
136
137static const struct component_master_ops hda_component_master_ops = {
138 .bind = hda_component_master_bind,
139 .unbind = hda_component_master_unbind,
140};
141
142static int hda_component_master_match(struct device *dev, void *data)
143{
144 /* i915 is the only supported component */
145 return !strcmp(dev->driver->name, "i915");
146}
147
148int hda_i915_init(struct hda_intel *hda)
149{
150 struct component_match *match = NULL;
151 struct device *dev = &hda->chip.pci->dev;
152 struct i915_audio_component *acomp = &hda->audio_component;
153 int ret;
154
155 component_match_add(dev, &match, hda_component_master_match, hda);
156 ret = component_master_add_with_match(dev, &hda_component_master_ops,
157 match);
158 if (ret < 0)
159 goto out_err;
160
161 /*
162 * Atm, we don't support deferring the component binding, so make sure
163 * i915 is loaded and that the binding successfully completes.
164 */
165 request_module("i915");
166
167 if (!acomp->ops) {
168 ret = -ENODEV;
169 goto out_master_del;
103 } 170 }
104 171
105 get_cdclk = symbol_request(i915_get_cdclk_freq); 172 dev_dbg(dev, "bound to i915 component master\n");
106 if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */
107 pr_warn("hda-i915: get_cdclk symbol get fail\n");
108 173
109 pr_debug("HDA driver get symbol successfully from i915 module\n"); 174 return 0;
175out_master_del:
176 component_master_del(dev, &hda_component_master_ops);
177out_err:
178 dev_err(dev, "failed to add i915 component master (%d)\n", ret);
110 179
111 return err; 180 return ret;
112} 181}
113 182
114int hda_i915_exit(struct hda_intel *hda) 183int hda_i915_exit(struct hda_intel *hda)
115{ 184{
116 if (get_power) { 185 struct device *dev = &hda->chip.pci->dev;
117 symbol_put(i915_request_power_well); 186
118 get_power = NULL; 187 component_master_del(dev, &hda_component_master_ops);
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 188
129 return 0; 189 return 0;
130} 190}
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 323abf952d00..95a539993990 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1890,11 +1890,8 @@ static int azx_probe_continue(struct azx *chip)
1890 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { 1890 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
1891#ifdef CONFIG_SND_HDA_I915 1891#ifdef CONFIG_SND_HDA_I915
1892 err = hda_i915_init(hda); 1892 err = hda_i915_init(hda);
1893 if (err < 0) { 1893 if (err < 0)
1894 dev_err(chip->card->dev,
1895 "Error request power-well from i915\n");
1896 goto out_free; 1894 goto out_free;
1897 }
1898 err = hda_display_power(hda, true); 1895 err = hda_display_power(hda, true);
1899 if (err < 0) { 1896 if (err < 0) {
1900 dev_err(chip->card->dev, 1897 dev_err(chip->card->dev,
diff --git a/sound/pci/hda/hda_intel.h b/sound/pci/hda/hda_intel.h
index 70b8306fec23..348611835476 100644
--- a/sound/pci/hda/hda_intel.h
+++ b/sound/pci/hda/hda_intel.h
@@ -16,6 +16,7 @@
16#ifndef __SOUND_HDA_INTEL_H 16#ifndef __SOUND_HDA_INTEL_H
17#define __SOUND_HDA_INTEL_H 17#define __SOUND_HDA_INTEL_H
18 18
19#include <drm/i915_component.h>
19#include "hda_priv.h" 20#include "hda_priv.h"
20 21
21struct hda_intel { 22struct hda_intel {
@@ -41,6 +42,9 @@ struct hda_intel {
41 42
42 /* secondary power domain for hdmi audio under vga device */ 43 /* secondary power domain for hdmi audio under vga device */
43 struct dev_pm_domain hdmi_pm_domain; 44 struct dev_pm_domain hdmi_pm_domain;
45
46 /* i915 component interface */
47 struct i915_audio_component audio_component;
44}; 48};
45 49
46#ifdef CONFIG_SND_HDA_I915 50#ifdef CONFIG_SND_HDA_I915